PageSourceSearch

https://farm-nightly.netlify.app/assets/js/ed2294ad.8a1d16d6.js

js farm-nightly.netlify.app collected 2026-10-03 10:45:20 UTC 10,639 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[6600],{87501:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>u,contentTitle:()=>s,default:()=>c,frontMatter:()=>t,metadata:()=>o,toc:()=>a});var r=i(49214),l=i(36906);const t={},s="Writing Runtime Plugin",o={id:"plugins/writing-plugins/runtime-plugin",title:"Writing Runtime Plugin",description:"A Farm runtime plugin is a pure javascript object that define a set of hooks to enhance Farm runtime. Example:",source:"@site/docs/plugins/writing-plugins/runtime-plugin.md",sourceDirName:"plugins/writing-plugins",slug:"/plugins/writing-plugins/runtime-plugin",permalink:"/docs/plugins/writing-plugins/runtime-plugin",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/plugins/writing-plugins/runtime-plugin.md",tags:[],version:"current",frontMatter:{},sidebar:"pluginSidebar",previous:{title:"Writing JavaScript Plugins",permalink:"/docs/plugins/writing-plugins/js-plugin"}},u={},a=[{value:"Caveat",id:"caveat",level:2},{value:"Conventions",id:"conventions",level:2},{value:"Using Runtime Plugins",id:"using-runtime-plugins",level:2},{value:"Writing Runtime Plugins",id:"writing-runtime-plugins",level:2},{value:"Create a Plugin",id:"create-a-plugin",level:3},{value:"Debug the Plugin",id:"debug-the-plugin",level:3},{value:"Publish the Plugin(Optional)",id:"publish-the-pluginoptional",level:3},{value:"Runtime Plugin Hooks",id:"runtime-plugin-hooks",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"writing-runtime-plugin",children:"Writing Runtime Plugin"})}),"\n",(0,r.jsx)(n.p,{children:"A Farm runtime plugin is a pure javascript object that define a set of hooks to enhance Farm runtime. Example:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"/**\n * HMR client as a Farm Runtime Plugin\n */\nimport type { Plugin } from '@farmfe/runtime';\nimport { createHotContext } from './hot-module-state';\nimport { HmrClient } from './hmr-client';\n\nlet hmrClient: HmrClient;\n// export a Farm runtime plugin object\nexport default <Plugin>{\n  name: 'farm-runtime-hmr-client-plugin',\n  // define hooks\n  bootstrap(moduleSystem) {\n    hmrClient = new HmrClient(moduleSystem);\n    hmrClient.connect();\n  },\n  moduleCreated(module) {\n    // create a hot context for each module\n    module.meta.hot = createHotContext(module.id, hmrClient);\n  }\n};\n"})}),"\n",(0,r.jsx)(n.p,{children:"Above it's a runtime plugin that supports HMR for Farm. Essentials:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["A runtime plugin entry file should ",(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"export"})})," a default object that defines a set of hooks. e.g ",(0,r.jsx)(n.code,{children:"export default <Plugin>{/*...*/}"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"name"})," is required to identify the plugin, make sure ",(0,r.jsx)(n.code,{children:"name"})," is unique"]}),"\n",(0,r.jsxs)(n.li,{children:["A ",(0,r.jsx)(n.code,{children:"hook"})," is a method that defined in the exported object."]}),"\n"]}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["See ",(0,r.jsx)(n.a,{href:"https://github.com/farm-fe/farm/tree/main/packages/runtime-plugin-hmr",children:"@farmfe/runtime-plugin-hmr"})," for full implementation of above examples."]})}),"\n",(0,r.jsx)(n.h2,{id:"caveat",children:"Caveat"}),"\n",(0,r.jsxs)(n.p,{children:["You should make your runtime plugin as ",(0,r.jsx)(n.strong,{children:"simple"})," as possible. You ",(0,r.jsx)(n.strong,{children:"SHOULD NOT"}),":"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Use ",(0,r.jsx)(n.strong,{children:"big dependencies"})," from node_modules, this would make your farm plugin very large, it's really bad for performance."]}),"\n",(0,r.jsxs)(n.li,{children:["Use new features like ",(0,r.jsx)(n.code,{children:"top level await"})," as these runtime related features are hard to polyfill for low level runtime."]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["It's really recommended to make sure your runtime plugin ",(0,r.jsx)(n.strong,{children:"as small and simple as possible"}),"."]}),"\n",(0,r.jsx)(n.admonition,{type:"tip",children:(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"import.meta.xxx"})," will be compiled to ",(0,r.jsx)(n.code,{children:"module.meta.xxx"}),", you can ",(0,r.jsx)(n.code,{children:"append values"})," to ",(0,r.jsx)(n.code,{children:"module.meta"})," in runtime plugins to enhance ",(0,r.jsx)(n.code,{children:"import.meta"}),". For example, ",(0,r.jsx)(n.code,{children:"module.meta.hot = createHotContext(module.id, hmrClient)"})," makes ",(0,r.jsx)(n.code,{children:"import.meta.hot"})," available."]})}),"\n",(0,r.jsx)(n.h2,{id:"conventions",children:"Conventions"}),"\n",(0,r.jsxs)(n.p,{children:["A Farm runtime plugin name should be prefixed by ",(0,r.jsx)(n.code,{children:"farm-runtime-plugin"}),", e.g ",(0,r.jsx)(n.code,{children:"farm-runtime-plugin-xxx"}),"."]}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["Both ",(0,r.jsx)(n.code,{children:"plugin.name"})," and ",(0,r.jsx)(n.code,{children:"package name"}),"(Only if you publish your plugin as a package) should be prefixed."]})}),"\n",(0,r.jsx)(n.h2,{id:"using-runtime-plugins",children:"Using Runtime Plugins"}),"\n",(0,r.jsxs)(n.p,{children:["Use ",(0,r.jsx)(n.code,{children:"compilation.runtime.plugins"})," to configure runtime plugins for your project:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';
1\n\nexport default defineConfig({\n  compilation: {\n    runtime: {\n      plugins: [\n        // relative path\n        './src/my-plugin1.ts',\n        // absolute path\n        '/root/project/src/my-plugin2.ts',\n        // package name\n        '@scope/plugin-package-from-node-modules'\n      ]\n    }\n  }\n});\n"})}),"\n",(0,r.jsx)(n.p,{children:"You can configure runtime plugin item by 3 ways:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"relative path"})}),":  Path that is relative to ",(0,r.jsx)(n.code,{children:"root"}),", e.g ",(0,r.jsx)(n.code,{children:"./src/my-plugin1.ts"})," will try load plugin from ",(0,r.jsx)(n.code,{children:"<root>/src/my-plugin1.ts"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"absolute path"})}),":  e.g ",(0,r.jsx)(n.code,{children:"/root/project/src/my-plugin2.ts"}),". (Absolute path should be ",(0,r.jsx)(n.code,{children:"C:\\project\\src\\my-plugin2.ts"})," on windows)."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"package name"})}),":  Farm will try load this package from ",(0,r.jsx)(n.code,{children:"node_modules"}),", e.g ",(0,r.jsx)(n.code,{children:"@scope/plugin-package-from-node-modules"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"writing-runtime-plugins",children:"Writing Runtime Plugins"}),"\n",(0,r.jsxs)(n.admonition,{type:"tip",children:[(0,r.jsxs)(n.p,{children:["Farm support loading ",(0,r.jsx)(n.code,{children:".ts"})," file directly, so you can configure a ",(0,r.jsx)(n.code,{children:".ts"})," file(or a package whose entry is a ",(0,r.jsx)(n.code,{children:"ts"})," file) in ",(0,r.jsx)(n.code,{children:"runtime.plugins"})," directly."]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"export default defineConfig({\n  compilation: {\n    runtime: {\n      plugins: [\n        // configuring ts file directly\n        './src/my-plugin.ts',\n      ]\n    }\n  }\n});\n"})})]}),"\n",(0,r.jsx)(n.h3,{id:"create-a-plugin",children:"Create a Plugin"}),"\n",(0,r.jsx)(n.p,{children:"As we mentioned above, a Farm runtime plugin is a pure javascript object that define a set of hooks, you can just create a ts file like:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",metastring:'title="./plugins/runtime.ts"',children:"import type { Plugin } from '@farmfe/runtime';\n\nexport default <Plugin> {\n  name: 'my-plugin',\n  // ...\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Then define ",(0,r.jsx)(n.a,{href:"#runtime-plugin-hooks",children:"hooks"})," you need in the exported object:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",metastring:'title="./plugins/runtime.ts"',children:"import type { Plugin } from '@farmfe/runtime';\n\nexport default <Plugin> {\n  name: 'my-plugin',\n  moduleCreated(module) {\n    // ...\n  },\n  readModuleCache(module) {\n    // ...\n  },\n  loadResource(resource, targetEnv) {\n    // ...\n  },\n  // ... more hooks as long as you need\n}\n"})}),"\n",(0,r.jsx)(n.h3,{id:"debug-the-plugin",children:"Debug the Plugin"}),"\n",(0,r.jsxs)(n.p,{children:["Configure the plugin you created in ",(0,r.jsx)(n.code,{children:"runtime.plugins"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"export default defineConfig({\n  compilation: {\n    runtime: {\n      plugins: [\n        './plugins/runtime.ts',\n      ]\n    }\n  }\n});\n"})}),"\n",(0,r.jsx)(n.p,{children:"Then start the Farm project, this plugin will be injected in the runtime of output resources."}),"\n",(0,r.jsx)(n.h3,{id:"publish-the-pluginoptional",children:"Publish the Plugin(Optional)"}),"\n",(0,r.jsxs)(n.p,{children:["You can publish the runtime plugin to npm registry to share your Farm runtime plugin. Just create a ",(0,r.jsx)(n.code,{children:"package.json"})," like:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n  "name": "@farmfe/runtime-plugin-hmr",\n  "version": "3.4.2",\n  "description": "Runtime hmr plugin of Farm",\n  // c-highlight-start\n  "main": "src/index.ts",\n  // c-highlight-end\n  // ... ignore other fields\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You can just export ",(0,r.jsx)(n.code,{children:"ts"})," file using ",(0,r.jsx)(n.code,{children:'"main": "src/index.ts"'}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"runtime-plugin-hooks",children:"Runtime Plugin Hooks"}),"\n",(0,r.jsxs)(n.p,{children:["See ",(0,r.jsx)(n.a,{href:"/docs/api/runtime-plugin-api",children:"Runtime Plugin API"})]})]})}function c(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.