|
| 1 | +const path = require('path'); |
| 2 | +const loaderUtils = require('loader-utils'); |
| 3 | +const postcss = require('postcss'); |
| 4 | + |
| 5 | +const localByDefault = require('postcss-modules-local-by-default'); |
| 6 | +const modulesScope = require('postcss-modules-scope'); |
| 7 | + |
| 8 | +const postCssPlugins = require('./postcss-plugins'); |
| 9 | +const extractThemeRulesPlugin = postCssPlugins.extractThemeRulesPlugin; |
| 10 | +const removeCssModuleExports = postCssPlugins.removeCssModuleExports; |
| 11 | + |
| 12 | +const stringifyRuleMap = (ruleMap) => { |
| 13 | + return Object.keys(ruleMap).reduce((acc, selector) => { |
| 14 | + const declsMap = ruleMap[selector]; |
| 15 | + const decls = Object.keys(declsMap).map(prop => `${prop}: ${declsMap[prop]};`); |
| 16 | + |
| 17 | + return `${selector} {\n\t${decls.join('\n\t')}\n}`; |
| 18 | + }, ''); |
| 19 | +}; |
| 20 | + |
| 21 | +// copied from css-loader/lib/getLocalIdent.js |
| 22 | +function getLocalIdent(loaderContext, localIdentName, localName, options) { |
| 23 | + if(!options.context) |
| 24 | + options.context = loaderContext.options && typeof loaderContext.options.context === "string" ? loaderContext.options.context : loaderContext.context; |
| 25 | + var request = path.relative(options.context, loaderContext.resourcePath); |
| 26 | + options.content = options.hashPrefix + request + "+" + localName; |
| 27 | + localIdentName = localIdentName.replace(/\[local\]/gi, localName); |
| 28 | + var hash = loaderUtils.interpolateName(loaderContext, localIdentName, options); |
| 29 | + return hash.replace(new RegExp("[^a-zA-Z0-9\\-_\u00A0-\uFFFF]", "g"), "-").replace(/^([^a-zA-Z_])/, "_$1"); |
| 30 | +}; |
| 31 | + |
| 32 | + |
| 33 | +module.exports = function (source, map) { |
| 34 | + if ( this.cacheable ) this.cacheable(); |
| 35 | + |
| 36 | + var loader = this; |
| 37 | + var file = loader.resourcePath; |
| 38 | + |
| 39 | + var callback = loader.async(); |
| 40 | + |
| 41 | + var plugins = [extractThemeRulesPlugin]; |
| 42 | + |
| 43 | + Promise.resolve().then(function (config) { |
| 44 | + return postcss(plugins).process(source).then(function (result) { |
| 45 | + result.warnings().forEach(function (msg) { |
| 46 | + loader.emitWarning(msg.toString()); |
| 47 | + }); |
| 48 | + |
| 49 | + if (result.ruleMap) { |
| 50 | + const content = stringifyRuleMap(result.ruleMap); |
| 51 | + |
| 52 | + return { |
| 53 | + css: result.css, |
| 54 | + map: result.map ? result.map.toJSON() : null, |
| 55 | + themeCss: content |
| 56 | + }; |
| 57 | + } |
| 58 | + |
| 59 | + // pass through unaffected css |
| 60 | + callback(null, source, map); |
| 61 | + return null; |
| 62 | + }); |
| 63 | + }).then(function (prevResult) { |
| 64 | + const content = prevResult.themeCss; |
| 65 | + |
| 66 | + const options = loaderUtils.getOptions(loader) || {}; |
| 67 | + const localIdentName = options.localIdentName || '[hash:base64]'; |
| 68 | + const customGetLocalIdent = options.getLocalIdent || getLocalIdent; |
| 69 | + |
| 70 | + // convert local classnames for css modules |
| 71 | + return postcss([ |
| 72 | + localByDefault({ |
| 73 | + mode: 'local' |
| 74 | + }), |
| 75 | + modulesScope({ |
| 76 | + generateScopedName: function generateScopedName (exportName) { |
| 77 | + return customGetLocalIdent(loader, localIdentName, exportName, { |
| 78 | + regExp: options.localIdentRegExp, |
| 79 | + hashPrefix: options.hashPrefix || '', |
| 80 | + context: loader.options.context |
| 81 | + }); |
| 82 | + } |
| 83 | + }), |
| 84 | + removeCssModuleExports |
| 85 | + ]).process(content).then(function (result) { |
| 86 | + result.warnings().forEach(function (msg) { |
| 87 | + loader.emitWarning(msg.toString()); |
| 88 | + }); |
| 89 | + |
| 90 | + if ('_emitThemePartial' in loader) { |
| 91 | + loader._emitThemePartial(result.css); |
| 92 | + } else { |
| 93 | + throw new Error('Theme loader missing _emitThemePartial function. Did you forget to include the ThemePlugin?'); |
| 94 | + } |
| 95 | + |
| 96 | + callback(null, prevResult.css, prevResult.map); |
| 97 | + return null; |
| 98 | + }); |
| 99 | + }).catch(function (error) { |
| 100 | + callback(error); |
| 101 | + }); |
| 102 | +}; |
0 commit comments