如何从webpack插件生成模块并热替换它

时间:2017-01-03 20:29:43

标签: javascript webpack-hmr webpack-plugin

我正在尝试为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发生变化时,我都会渲染一个新版本的小模块,迫使样式表重新加载。然后我会让web pack的热模块替换替换该模块,因此实际上对提取的样式表具有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吧,对吗?

0 个答案:

没有答案