Frontend Dynamic Provider Plugin Principle
provider
For each compiled component, it can be wrapped by introducing a provider to achieve unified use of some environment variables and styles. You can introduce it yourself, or you don't need to write it, define a plugin to automatically implement the introduction.
import BusinessFieldSetting from './Views/BusinessFieldSetting'
import Setting from '@/components/Setting/Setting'
import { provider } from '@/provider/index'
import field from '@/assets/svg/field.svg'
export default {
is: 'BusinessFieldSetting',
name: 'Business Field Setting',
category: 'run',
icon: field,
authorizationRequired: true,
canvasView: provider(BusinessFieldSetting), <--- provider here
settingsView: Setting,
}
Plugin Implementation Principle:
The Vite plugin is named vite-plugin-widget-provider, specifically designed to automatically process component entry files under the src/widgets/**/index.ts path during the build phase, improving component encapsulation consistency and development efficiency. The plugin matches all .ts files by constructing a regular expression, and further screens out index.ts files under the widgets directory as targets.
The core logic is divided into two steps:
-
First, extract the
importblock,export defaultcontent, andcanvasViewfield in the file through theparseCodefunction; -
Secondly, in
mergeCodeString, determine whether thecanvasViewfield has been wrapped withprovider(). If it is not wrapped andprovider/indexis not introduced, automatically insertimport { provider } from "@/provider/index", and convert the originalcanvasView: SomeComponenttocanvasView: provider(SomeComponent).
This transformation is completed through the transform hook provided by Vite, which can directly replace the target file content, thereby realizing automatic component wrapping and context capability injection. The plugin only takes effect in apply: 'build' mode, ensuring that it does not affect development debugging. The overall design logic is clear, avoiding repetitive injection and manual operations, and has good scalability and maintainability in multi-component development scenarios.
import path from 'path'
const isWin = process.platform === 'win32'
const fileRegex = /\.(ts)$/
const basePath = path.resolve(process.cwd(), './src/widgets')
const filePath = isWin ? basePath.replaceAll('\\', '/') : basePath
const regex = new RegExp(`${filePath}/([^/]*)/index.ts`)
const NOT_PAGE = 'notPage:true'
/**
* Extract key characters
* @param {*} code
* @returns
*/
const parseCode = (code) => {
const importRegion = code.match(/import[^]*?("|')(.*?)\1;/g)
const exportDefaultRegion = code.match(/export default [\s\S]*?;/)
const canvasView = code.match(/canvasView: ([^,]+),/)
const canvasViewValue = canvasView ? canvasView[1] : ''
const imports = importRegion ? importRegion.join('\n') : ''
const exportDefault = exportDefaultRegion ? exportDefaultRegion[0] : ''
return { imports, exportDefault, canvasView: canvasView[0], canvasViewValue }
}
/**
* Merge processing code
* @param {*} param0
* @param {*} originCode
*/
const mergeCodeString = (
{ imports, exportDefault, canvasView, canvasViewValue },
originCode
) => {
const code = `${imports}\n${exportDefault}`
if (
canvasView.includes('provider(') &&
originCode.includes('provider/index')
) {
return code
}
const providerCode = 'import { provider } from "@/provider/index";'
const exportDefaultCode = exportDefault.replace(
canvasView,
`canvasView: provider(${canvasViewValue}),`
)
return `${imports}\n${providerCode}\n${exportDefaultCode}`
}
export default function VitePluginWidgetProvider(): any {
return {
name: 'vite-plugin-widget-provider',
apply: 'build',
transform(code, id) {
if (fileRegex.test(id)) {
if (regex.test(id)) {
const codeData = parseCode(code)
const transformCode = mergeCodeString(codeData, code)
// const emptyCode = code.replaceAll(' ', '')
const newCode = transformCode
// const newCode = emptyCode.includes(NOT_PAGE) ? code : transformCode
return {
code: newCode,
map: null, // Provide source map if feasible
}
}
}
},
}
}