Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Images in css not emitted on subsequent builds when using mini-css-extract-plugin with non-persistent build #367

Closed
OscarBarrett opened this issue May 31, 2018 · 5 comments

Comments

@OscarBarrett
Copy link

OscarBarrett commented May 31, 2018

Expected Behavior

When the webpack build is not persisted (e.g. when using something like clean-webpack-plugin, or webpack-dev-server with contentBase set to false), images referenced in css files should be emitted on subsequent builds if they no longer exist on disk.

Actual Behavior

When using mini-css-extract-plugin, images referenced in css files are not emitted on subsequent builds. With only css-loader they are.

Is an error being thrown?

No

Steps to Reproduce

Minimal reproduction here

Operating System, Node, and NPM dependency versions

Linux, MacOS
Node 8.10

"devDependencies": {
  "clean-webpack-plugin": "^0.1.19",
  "css-loader": "^0.28.11",
  "file-loader": "^1.1.11",
  "hard-source-webpack-plugin": "^0.7.4",
  "mini-css-extract-plugin": "^0.4.0",
  "webpack": "^4.10.2",
  "webpack-cli": "^2.1.4",
  "webpack-dev-server": "^3.1.4"
}
@OscarBarrett OscarBarrett changed the title Images in css not emitted on subsequent builds when using mini-css-extract-plugin invalid May 31, 2018
@OscarBarrett
Copy link
Author

Sorry... I wrote up the issue with a reproduction but realised that it didn't match the exact problem. Updated with more info about specific cases where this can happen (when the build is not persisted).

@OscarBarrett OscarBarrett reopened this May 31, 2018
@OscarBarrett OscarBarrett changed the title invalid Images in css not emitted on subsequent builds when using mini-css-extract-plugin with non-persistent build May 31, 2018
@mzgoddard
Copy link
Owner

@OscarBarrett Thank you for opening this issue. I'm going to file a bug in mini-css for this. It is a bug in mini-css that it does not lift assets to the parent module.

@mzgoddard
Copy link
Owner

I'll see if I can implement #76 as a workaround. If you were to exclude /mini-css-extract-plugin[\\/]dist[\\/]loader/ modules it would have to rebuild part of the process that will rebuild images.

@piecyk
Copy link
Contributor

piecyk commented Jun 5, 2018

Having the same problem, basic

"hard-source-webpack-plugin": "0.7.5",
"mini-css-extract-plugin": "0.4.0",
"webpack": "4.10.2",
"file-loader": "1.1.11",

On next run, when reading from cache fonts are not loaded... They are included in stylus file, loaded into webpack with file-loader... Editing file that includes it bring them back...

@piecyk
Copy link
Contributor

piecyk commented Jun 13, 2018

Did some digging and it looks like that, mini-css-extract-plugin when running the plugin will replace module dependencies as described in PR#117 that breaks the track of assets...

As temporary workaround, wrote an plugin that will collect assets for that dependencies

const hasCssLoader = (loaders = []) => loaders.find(l => l.loader.indexOf('css-loader') !== -1)

// This will collect assets from dependencies,
// use only with hard-source-webpack-plugin, to link assets in next run!
// Remove this after https://github.com/webpack-contrib/mini-css-extract-plugin/pull/177

export default class LinkCssAssetsToIssuerPlugin {
  apply(compiler) {
    let parentAssets = {}

    const collect = module => {
      if (module.issuer && hasCssLoader(module.issuer.loaders)) {
        const bi = module.buildInfo
        const hasAssets = bi && bi.assets && Object.keys(bi.assets).length > 0
        if (hasAssets) {
          const parent = module.issuer.resource
          parentAssets = {
            ...parentAssets,
            [parent]: { ...parentAssets[parent], ...bi.assets },
          }
        }
      }

      const assets = parentAssets[module.resource]
      if (assets) {
        module.buildInfo = module.buildInfo || { assets: {} }
        module.buildInfo.assets = { ...module.buildInfo.assets, ...assets }
      }
    }

    compiler.hooks.compilation.tap('LinkCssAssetsToIssuerPlugin', compilation => {
      compilation.hooks.succeedModule.tap('LinkCssAssetsToIssuerPlugin succeedModule', collect)
      compilation.hooks.failedModule.tap('LinkCssAssetsToIssuerPlugin failedModule', collect)
    })
  }
}

save this as LinkCssAssetsToIssuerPlugin.js and include next to HardSourceWebpackPlugin
in webpack plugins

// webpack.config.js
plugins: [
  new LinkCssAssetsToIssuerPlugin(),
  new HardSourceWebpackPlugin()
  // ...
]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants