From 4f76812cd83ecd5d39e877e2f5bc1a7adeca7e76 Mon Sep 17 00:00:00 2001 From: David Liu Date: Tue, 17 Mar 2020 22:43:59 +0800 Subject: [PATCH] feat: add `exportGlobals` option --- README.md | 28 +++++++++++++++++ src/options.json | 3 ++ src/utils.js | 2 ++ .../__snapshots__/modules-option.test.js.snap | 31 +++++++++++++++++++ .../validate-options.test.js.snap | 25 +++++++++------ .../modules/exportGlobals/exportGlobals.css | 3 ++ .../modules/exportGlobals/exportGlobals.js | 5 +++ test/modules-option.test.js | 18 +++++++++++ test/validate-options.test.js | 2 ++ 9 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 test/fixtures/modules/exportGlobals/exportGlobals.css create mode 100644 test/fixtures/modules/exportGlobals/exportGlobals.js diff --git a/README.md b/README.md index 8020201e..58ed7eb7 100644 --- a/README.md +++ b/README.md @@ -531,6 +531,7 @@ module.exports = { localIdentName: '[path][name]__[local]--[hash:base64:5]', context: path.resolve(__dirname, 'src'), hashPrefix: 'my-custom-hash', + exportGlobals: true, }, }, }, @@ -886,6 +887,33 @@ module.exports = { }; ``` +### `exportGlobals` + +Type: `Boolean` +Default: `false` + +Allow `css-loader` to export names from global class or id, so you can use that as local name. + +**webpack.config.js** + +```js +module.exports = { + module: { + rules: [ + { + test: /\.css$/i, + loader: 'css-loader', + options: { + modules: { + exportGlobals: true, + }, + }, + }, + ], + }, +}; +``` + ## Examples ### Assets diff --git a/src/options.json b/src/options.json index 77015844..cd4c033a 100644 --- a/src/options.json +++ b/src/options.json @@ -67,6 +67,9 @@ "instanceof": "Function" } ] + }, + "exportGlobals": { + "type": "boolean" } } } diff --git a/src/utils.js b/src/utils.js index cd53cbeb..b8acecc5 100644 --- a/src/utils.js +++ b/src/utils.js @@ -103,6 +103,7 @@ function getModulesPlugins(options, loaderContext) { getLocalIdent, hashPrefix: '', localIdentRegExp: null, + exportGlobals: false, }; if ( @@ -147,6 +148,7 @@ function getModulesPlugins(options, loaderContext) { return localIdent; }, + exportGlobals: modulesOptions.exportGlobals, }), ]; } diff --git a/test/__snapshots__/modules-option.test.js.snap b/test/__snapshots__/modules-option.test.js.snap index 85e61ce9..3c30ce20 100644 --- a/test/__snapshots__/modules-option.test.js.snap +++ b/test/__snapshots__/modules-option.test.js.snap @@ -10811,6 +10811,37 @@ Array [ exports[`"modules" option should work with case \`values-10\` (\`modules\` value is \`true)\`: warnings 1`] = `Array []`; +exports[`"modules" option should work with exportGlobals option: errors 1`] = `Array []`; + +exports[`"modules" option should work with exportGlobals option: module 1`] = ` +"// Imports +var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../../src/runtime/api.js\\"); +exports = ___CSS_LOADER_API_IMPORT___(false); +// Module +exports.push([module.id, \\".foo {\\\\n background-color: #ffffff;\\\\n}\\\\n\\", \\"\\"]); +// Exports +exports.locals = { + \\"foo\\": \\"foo\\" +}; +module.exports = exports; +" +`; + +exports[`"modules" option should work with exportGlobals option: result 1`] = ` +Array [ + Array [ + "./modules/exportGlobals/exportGlobals.css", + ".foo { + background-color: #ffffff; +} +", + "", + ], +] +`; + +exports[`"modules" option should work with exportGlobals option: warnings 1`] = `Array []`; + exports[`"modules" option should work with the "[local]" placeholder for the "localIdentName" option: errors 1`] = `Array []`; exports[`"modules" option should work with the "[local]" placeholder for the "localIdentName" option: module 1`] = ` diff --git a/test/__snapshots__/validate-options.test.js.snap b/test/__snapshots__/validate-options.test.js.snap index f65d36cc..172ad39c 100644 --- a/test/__snapshots__/validate-options.test.js.snap +++ b/test/__snapshots__/validate-options.test.js.snap @@ -48,10 +48,15 @@ exports[`validate options should throw an error on the "modules" option with "{" - options.modules.context should be a string." `; +exports[`validate options should throw an error on the "modules" option with "{"exportGlobals":"invalid"}" value 1`] = ` +"Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. + - options.modules.exportGlobals should be a boolean." +`; + exports[`validate options should throw an error on the "modules" option with "{"getLocalIdent":[]}" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent?, exportGlobals? } -> Enables/Disables CSS Modules and their configuration (https://github.com/webpack-contrib/css-loader#modules). Details: * options.modules.getLocalIdent should be one of these: @@ -74,7 +79,7 @@ exports[`validate options should throw an error on the "modules" option with "{" exports[`validate options should throw an error on the "modules" option with "{"localIdentRegExp":true}" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent?, exportGlobals? } -> Enables/Disables CSS Modules and their configuration (https://github.com/webpack-contrib/css-loader#modules). Details: * options.modules.localIdentRegExp should be one of these: @@ -111,53 +116,53 @@ exports[`validate options should throw an error on the "modules" option with "{" exports[`validate options should throw an error on the "modules" option with "globals" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent?, exportGlobals? } -> Enables/Disables CSS Modules and their configuration (https://github.com/webpack-contrib/css-loader#modules). Details: * options.modules should be a boolean. * options.modules should be one of these: \\"local\\" | \\"global\\" | \\"pure\\" * options.modules should be an object: - object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? }" + object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent?, exportGlobals? }" `; exports[`validate options should throw an error on the "modules" option with "locals" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent?, exportGlobals? } -> Enables/Disables CSS Modules and their configuration (https://github.com/webpack-contrib/css-loader#modules). Details: * options.modules should be a boolean. * options.modules should be one of these: \\"local\\" | \\"global\\" | \\"pure\\" * options.modules should be an object: - object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? }" + object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent?, exportGlobals? }" `; exports[`validate options should throw an error on the "modules" option with "pures" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent?, exportGlobals? } -> Enables/Disables CSS Modules and their configuration (https://github.com/webpack-contrib/css-loader#modules). Details: * options.modules should be a boolean. * options.modules should be one of these: \\"local\\" | \\"global\\" | \\"pure\\" * options.modules should be an object: - object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? }" + object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent?, exportGlobals? }" `; exports[`validate options should throw an error on the "modules" option with "true" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent?, exportGlobals? } -> Enables/Disables CSS Modules and their configuration (https://github.com/webpack-contrib/css-loader#modules). Details: * options.modules should be a boolean. * options.modules should be one of these: \\"local\\" | \\"global\\" | \\"pure\\" * options.modules should be an object: - object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? }" + object { mode?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent?, exportGlobals? }" `; exports[`validate options should throw an error on the "onlyLocals" option with "true" value 1`] = ` diff --git a/test/fixtures/modules/exportGlobals/exportGlobals.css b/test/fixtures/modules/exportGlobals/exportGlobals.css new file mode 100644 index 00000000..ae51b4c7 --- /dev/null +++ b/test/fixtures/modules/exportGlobals/exportGlobals.css @@ -0,0 +1,3 @@ +:global(.foo) { + background-color: #ffffff; +} diff --git a/test/fixtures/modules/exportGlobals/exportGlobals.js b/test/fixtures/modules/exportGlobals/exportGlobals.js new file mode 100644 index 00000000..17cc87d2 --- /dev/null +++ b/test/fixtures/modules/exportGlobals/exportGlobals.js @@ -0,0 +1,5 @@ +import css from './exportGlobals.css'; + +__export__ = css; + +export default css; diff --git a/test/modules-option.test.js b/test/modules-option.test.js index 6ba9d5fb..6f1a1c6f 100644 --- a/test/modules-option.test.js +++ b/test/modules-option.test.js @@ -565,4 +565,22 @@ describe('"modules" option', () => { expect(getWarnings(stats)).toMatchSnapshot('warnings'); expect(getErrors(stats)).toMatchSnapshot('errors'); }); + + it('should work with exportGlobals option', async () => { + const compiler = getCompiler('./modules/exportGlobals/exportGlobals.js', { + modules: { + exportGlobals: true, + }, + }); + const stats = await compile(compiler); + + expect( + getModuleSource('./modules/exportGlobals/exportGlobals.css', stats) + ).toMatchSnapshot('module'); + expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot( + 'result' + ); + expect(getWarnings(stats)).toMatchSnapshot('warnings'); + expect(getErrors(stats)).toMatchSnapshot('errors'); + }); }); diff --git a/test/validate-options.test.js b/test/validate-options.test.js index 969765e4..0b67f0ad 100644 --- a/test/validate-options.test.js +++ b/test/validate-options.test.js @@ -26,6 +26,7 @@ describe('validate options', () => { { getLocalIdent: () => {} }, { localIdentRegExp: 'page-(.*)\\.js' }, { localIdentRegExp: /page-(.*)\.js/ }, + { exportGlobals: true }, ], failure: [ 'true', @@ -41,6 +42,7 @@ describe('validate options', () => { { hashPrefix: true }, { getLocalIdent: [] }, { localIdentRegExp: true }, + { exportGlobals: 'invalid' }, ], }, sourceMap: {