const PLUGIN = 'CoreCSSModulesWebpackPlugin' const isLoader = loader => loader !== 'string' interface CoreCSSWebpackPluginOptions { suffix: string } export class CoreCSSWebpackPlugin { isDev: boolean = false suffix: string = '' constructor({ suffix = 'suffix' }: CoreCSSWebpackPluginOptions) { this.isDev = process.env.NODE_ENV === 'development' this.suffix = new Buffer(suffix || '').toString('base64').slice(0, 5) } apply(compiler) { compiler.hooks.compilation.tap(PLUGIN, compilation => { compilation.hooks.buildModule.tap(PLUGIN, module => { if (module.resource && module.resource.indexOf('/core-css/') >= 0) { // we need to find the css loader in the list of loaders for each module module.loaders && module.loaders.filter(isLoader).forEach(loader => { if (loader.loader.indexOf('/css-loader/') >= 0) { // use existing options or default to empty object loader.options = loader.options || {} // turn css-modules on loader.options.modules = true if ( loader.options.getLocalIdent && loader.options.getLocalIdent.name !== 'customGetLocalIdent' ) { // if css-loader is configured to use `getLocalIdentName` then we // want to wrap the original function and prepend it's return value const getLocalIdent = loader.options.getLocalIdent const customGetLocalIdent = (...args) => { return `${getLocalIdent(...args)}-${this.suffix}` } loader.options.getLocalIdent = customGetLocalIdent } else if (loader.options.localIdentName) { // if css-loader is configured to use `localIdentName`, then we // want to prepend the value to the suffix loader.options.localIdentName = `${ loader.options.localIdentName }-${this.suffix}` } else { // css-loader is not configured to do any custom transform // of classnames, set it up while accounting for dev/prod mode loader.options.localIdentName = this.isDev ? `[local]-[hash:base64:5]-${this.suffix}` : `[hash:base64:5]-${this.suffix}` } } }) } }) }) } }