postcss / postcss-mixins

PostCSS plugin for mixins
MIT License
466 stars 47 forks source link

Hot reloading of functional mixins does not work #145

Closed andgra closed 2 years ago

andgra commented 2 years ago

There are 2 issues:

  1. Cached require calls
  2. Sub-dependencies of the mixin files are not passed to the build tools like webpack (via helpers.result.messages)

1: According to this line: mixins[name] = { mixin: require(path), file: path } Function mixins are loaded using node require function. In development mode, this code might be called several times when the source code of function mixin is changed. But after the first load, required files will not be updated because of the require caching.

One solution would be to clear cached modules. Like this:

mixins[name] = { mixin: require(path), file: path }
delete require.cache[require.resolve(path)]

But if we take into the account the case when mixin has its own dependencies, we have to clear the cache for them too:

mixins[name] = { mixin: require(path), file: path }
let clearModuleCacheRecursively = (module) => {
  module.children.forEach(childModule => clearModuleCacheRecursively(childModule))
  delete require.cache[module.id]
}
let module = require.cache[require.resolve(path)]
if (module) {
  clearModuleCacheRecursively(module)
}

2: To fix the second issue, we just have to add each child dependency to the watch list alongside with clearing the cache. Something like this:

mixins[name] = { mixin: require(path), file: path }
let clearModuleCacheRecursively = (module, helpers) => {
  let moduleId = module.id
  module.children.forEach(childModule => {
    helpers.result.messages.push({
      type: 'dependency',
      file: childModule.id,
      parent: moduleId
    })
    clearModuleCacheRecursively(childModule, helpers)
  })
  delete require.cache[moduleId]
}
let module = require.cache[require.resolve(path)]
if (module) {
  clearModuleCacheRecursively(module, helpers)
}

Another, "in-place", solution would be to create a custom postcss plugin that will do these steps after the main plugin as it is. But this solution looks like a hack.

I can create a PR with these changes.

ai commented 2 years ago

Yes, this looks like very useful feature. I am scary to implement it by my own. Waiting for PR.

ai commented 2 years ago

Can we close it?

andgra commented 2 years ago

Yes, thank you