Как сгенерировать модуль из плагина веб-пакета и заменить его?

Я пытаюсь написать плагин для веб-пакета для https://github.com/martinandert/babel-plugin-css-in-js, со следующими 2 требованиями во время разработки:

  • Я не хочу, чтобы файл записывался на диск, но вместо этого пусть 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, я бы представлял новую версию крошечного модуля, который заставляет таблицу стилей перезагружаться. Затем я бы заменил этот модуль на "Горячую замену модуля" веб-пакета, таким образом, в сущности, у 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)
    })
  })
}

И код плагина webpack для генерации файла с хешем последней версии CSS выглядит так:

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://stackru.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 перегрузчика не восстанавливается, что, я думаю, связано с тем, что исходный источник не изменяется, он будет меняться только во время компиляции.


Мои вопросы в основном:

  • Правильно ли я подхожу к этому? И знаете ли вы о правильных примерах, на которые я должен смотреть?
  • В качестве альтернативы, есть ли способ для меня скомпилировать файл без использования внешнего входного файла, но полностью из исходного кода? Таким образом, я могу просто заново сгенерировать исходный код и встроить хеш самостоятельно, после чего веб-пакет должен заметить разницу и HMR, не так ли?

0 ответов

Другие вопросы по тегам