我正在尝试为https://github.com/martinandert/babel-plugin-css-in-js编写一个 webpack 插件,在开发过程中有以下两个要求:
- 我不希望将文件写入磁盘,而是让 webpack-dev-server 将文件托管在内存中。
- 我想要热重载来加载新提取的 CSS。
(问题在底部。)
不要写入磁盘
我已经能够使用如下代码做到这一点,但是在阅读了许多不同的示例之后,我仍然不能 100% 确定这是正确的方法。
compiler.plugin('emit', function(compilation, callback) {
compilation.chunks.forEach(function(chunk) {
chunk.modules.forEach(function(module) {
if (module.resource) {
var css = extractCSSFromFile(module.resource)
if (css) {
cache[module.resource] = css
}
}
})
})
var source = Object.values(cache).join('')
compilation.assets[bundleFile] = {
source: function() { return source },
size: function() { return source.length },
}
})
热重载
我的想法是,每当 CSS 发生变化时,我都会渲染一个新版本的小模块,它会强制样式表重新加载。然后我会让 webpack 的 Hot Module Replacement 替换该模块,因此实际上对提取的样式表有 HMR。这个重载模块看起来像:
if (module.hot) {
module.hot.accept()
module.hot.dispose(function() {
document.querySelectorAll('link[href="' + WEBPACK_BABEL_CSS_IN_JS_STYLESHEET_PATH + '"]').forEach(link => {
link.href = link.href.replace(/(\?\d+)?$/, '?' + WEBPACK_BABEL_CSS_IN_JS_STYLESHEET_HASH)
})
})
}
使用最新 CSS 的哈希生成文件的 webpack 插件代码如下所示:
compiler.plugin('emit', function(compilation, callback) {
// All of the previous code to extract the CSS...
var source = Object.values(cache).join('')
var sourceHash = crypto.createHash('md5').update(source).digest('hex')
var cssReloader = path.basename(bundleFile, '.css') + '_webpack-reloader.js'
var childCompiler = compilation.createChildCompiler('babel-css-in-js', {
filename: cssReloader,
})
childCompiler.apply(
new SingleEntryPlugin(
compiler.context,
path.join(__dirname, 'webpack-babel-css-in-js-client-template.js'),
path.join(publicPath, cssReloader))
)
childCompiler.apply(
new webpack.DefinePlugin({
WEBPACK_BABEL_CSS_IN_JS_STYLESHEET_PATH: JSON.stringify(path.join(publicPath, bundleFile)),
WEBPACK_BABEL_CSS_IN_JS_STYLESHEET_HASH: JSON.stringify(sourceHash),
})
)
// Completely cargo-culted from http://stackoverflow.com/a/38284256
// It is supposedly required for HMR to work.
childCompiler.plugin('compilation', (compilation) => {
if (compilation.cache) {
if (!compilation.cache[cssReloader]) {
compilation.cache[cssReloader] = {}
}
compilation.cache = compilation.cache[cssReloader]
}
})
childCompiler.runAsChild(function(err) {
if (err) {
callback(err)
}
callback()
})
})
然而,问题是我的重新加载器 JS 模块没有重新生成,我认为这是因为输入源没有改变,它只会在编译期间改变。
我的问题基本上是:
- 我以正确的方式接近这个吗?你知道我应该看的正确例子吗?
- 或者,有没有办法让我在不使用外部输入文件的情况下编译文件,但完全来自源代码?这样我就可以自己重新生成源代码并嵌入哈希,之后 webpack 应该会注意到差异并 HMR ,对吗?