Webpack 插件:如何向主块动态添加模块?
Webpack Plugin: How to add dynamically a Module to the main Chunk?
我正在开发一个 Webpack 插件,它基本上在块中寻找 css
资产,当它找到这样的资产时,应用一些 postCSS
插件 returns 2 个输出,一个应该继续使用 Extract-Text-Plugin
提取,另一个输出应该成为 chunk 中的 new module 注入它在运行时处于领先地位。
我唯一没能实现的部分是在 现有 块中创建 新模块 的部分。有什么指点/想法吗?
我设法从中创建了一个 新块 但没有 webpack 包装器,这意味着我无法为那块 css 支持 HMR并懒惰地加载它。
class ExtractTPAStylePlugin {
constructor(options) {
this._options = Object.assign({
pattern: [
/"\w+\([^\)]+\)"/
]
}, options);
}
extract(compilation, chunks) {
const promises = [];
chunks.forEach((chunk) => {
promises.push(
chunk.files
.filter(fileName => fileName.endsWith('.css'))
.map(file => postcss([extractStyles(this._options)])
.process(compilation.assets[file].source(), {from: file, to: file})
.then((result) => {
compilation.assets[file] = new RawSource(result.css);
const filename = file.replace('.css', fileSuffix);
const newChunk = new Chunk(filename);
newChunk.files = [filename];
newChunk.ids = [];
compilation.chunks.push(newChunk);
const extractedStyles = `(${addStylesTemplate})()`
.replace('__CSS__', JSON.stringify(result.extracted))
.replace('__ID__', file);
compilation.assets[filename] = new OriginalSource(extractedStyles);
}))
);
});
return Promise.all(promises);
}
apply(compiler) {
compiler.plugin('compilation', (compilation) => {
compilation.plugin('optimize-chunk-assets', (chunks, callback) => {
this.extract(compilation, chunks)
.then(() => callback())
.catch(callback);
});
});
}
}
module.exports = ExtractTPAStylePlugin;
好的,所以我设法从几个插件中收集了一些代码,成功的解决方案是将加载器注入一些伪造的导入文件,在该加载器中将整个 js 代码加载到主包中,并为 optimize-chunk-assets
阶段的结果放置一些占位符。
之后,在optimize-chunk-assets
中可以找到相关的chunk,用ReplaceSource
查找&替换placeholder。
如需灵感,您可以查看 plugin。
也许还有更多方法可以做到这一点。
我发现一个方便的方法是创建自定义 NormalModuleFactory
插件并将其与编译器挂钩。
插件接收模块请求和上下文(从哪里导入的内容)。有了它,您可以匹配请求和 return 您的模块源。简化后,它看起来像:
class CustomModuleFactoryPlugin {
apply (normalModuleFactory) {
// Tap in the factory hook.
normalModuleFactory.hooks.factory.tap(
'CustomModuleFactoryPlugin',
factory => (data, cb) => {
const { context } = data
const { request } = data.dependencies[0]
if (path.join(context, request).contains('/something/you/expect') {
return cb(null, new RawSource('Success!'))
}
return factory(data, cb)
}
)
}
}
我正在开发一个 Webpack 插件,它基本上在块中寻找 css
资产,当它找到这样的资产时,应用一些 postCSS
插件 returns 2 个输出,一个应该继续使用 Extract-Text-Plugin
提取,另一个输出应该成为 chunk 中的 new module 注入它在运行时处于领先地位。
我唯一没能实现的部分是在 现有 块中创建 新模块 的部分。有什么指点/想法吗?
我设法从中创建了一个 新块 但没有 webpack 包装器,这意味着我无法为那块 css 支持 HMR并懒惰地加载它。
class ExtractTPAStylePlugin {
constructor(options) {
this._options = Object.assign({
pattern: [
/"\w+\([^\)]+\)"/
]
}, options);
}
extract(compilation, chunks) {
const promises = [];
chunks.forEach((chunk) => {
promises.push(
chunk.files
.filter(fileName => fileName.endsWith('.css'))
.map(file => postcss([extractStyles(this._options)])
.process(compilation.assets[file].source(), {from: file, to: file})
.then((result) => {
compilation.assets[file] = new RawSource(result.css);
const filename = file.replace('.css', fileSuffix);
const newChunk = new Chunk(filename);
newChunk.files = [filename];
newChunk.ids = [];
compilation.chunks.push(newChunk);
const extractedStyles = `(${addStylesTemplate})()`
.replace('__CSS__', JSON.stringify(result.extracted))
.replace('__ID__', file);
compilation.assets[filename] = new OriginalSource(extractedStyles);
}))
);
});
return Promise.all(promises);
}
apply(compiler) {
compiler.plugin('compilation', (compilation) => {
compilation.plugin('optimize-chunk-assets', (chunks, callback) => {
this.extract(compilation, chunks)
.then(() => callback())
.catch(callback);
});
});
}
}
module.exports = ExtractTPAStylePlugin;
好的,所以我设法从几个插件中收集了一些代码,成功的解决方案是将加载器注入一些伪造的导入文件,在该加载器中将整个 js 代码加载到主包中,并为 optimize-chunk-assets
阶段的结果放置一些占位符。
之后,在optimize-chunk-assets
中可以找到相关的chunk,用ReplaceSource
查找&替换placeholder。
如需灵感,您可以查看 plugin。
也许还有更多方法可以做到这一点。
我发现一个方便的方法是创建自定义 NormalModuleFactory
插件并将其与编译器挂钩。
插件接收模块请求和上下文(从哪里导入的内容)。有了它,您可以匹配请求和 return 您的模块源。简化后,它看起来像:
class CustomModuleFactoryPlugin {
apply (normalModuleFactory) {
// Tap in the factory hook.
normalModuleFactory.hooks.factory.tap(
'CustomModuleFactoryPlugin',
factory => (data, cb) => {
const { context } = data
const { request } = data.dependencies[0]
if (path.join(context, request).contains('/something/you/expect') {
return cb(null, new RawSource('Success!'))
}
return factory(data, cb)
}
)
}
}