UNPKG

@best-shot/sfc-split-plugin

Version:

92 lines (70 loc) 2.05 kB
import path from 'node:path'; import { parse } from '@into-mini/sfc-transformer'; import slash from 'slash'; import VirtualModulesPlugin from 'webpack-virtual-modules'; export class SfcSplitPlugin extends VirtualModulesPlugin { PLUGIN_NAME = 'SfcSplitPlugin'; apply(compiler) { this.#expose(compiler); super.apply(compiler); } #expose(compiler) { const { PLUGIN_NAME } = this; const { NormalModule: { getCompilationHooks }, } = compiler.webpack; compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => { getCompilationHooks(compilation).loader.tap( PLUGIN_NAME, (loaderContext) => { Object.defineProperty(loaderContext, 'processSfcFile', { enumerable: true, configurable: false, value: (options) => { return this.#processSfcFile(options); }, }); }, ); }); } #inject(resourcePath, ext, content) { const src = path.resolve(resourcePath.replace(/\.vue$/, ext)); super.writeModule(src, content); return src; } #injectStyle(resourcePath, id, style) { return this.#inject( resourcePath, `-${id}.${style.lang ?? 'css'}`, style.content, ); } #injectStyles(resourcePath, styles) { const io = []; const css = styles?.length > 0 ? styles : []; css.forEach((style, idx) => { if (style?.content) { const src = this.#injectStyle(resourcePath, idx, style); io.push(src); } }); return io; } #injectTemplate(resourcePath, tpl) { return this.#inject(resourcePath, '.wxml', tpl); } #processSfcFile({ source, resourcePath }) { const { tpl, styles, code, config } = parse(source); const paths = []; const wxml = this.#injectTemplate(resourcePath, tpl); paths.push(wxml); const css = this.#injectStyles(resourcePath, styles); paths.push(...css); return { config, paths: paths.map((src) => slash(src)), script: code, }; } }