Repository: webpack-contrib/css-loader
Pull request #1140 (2020-07-28 13:28:33)

feat: add `icss` option
This PR contains a:

- [ ] **bugfix**
- [x] new **feature**
- [ ] **code refactor**
- [ ] **test update** <!-- if bug or feature is checked, this should be too -->
- [ ] **typo fix**
- [ ] **metadata update**

### Motivation / Use-Case

#1134 more broadly enabling other loaders to handle CSS Modules 



codecov[bot]: # [Codecov](https://codecov.io/gh/webpack-contrib/css-loader/pull/1140?src=pr&el=h1) Report
> Merging [#1140](https://codecov.io/gh/webpack-contrib/css-loader/pull/1140?src=pr&el=desc) into [master](https://codecov.io/gh/webpack-contrib/css-loader/commit/bc7b18db5a46cf7446e45a11e13a8aeb83312c20&el=desc) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/webpack-contrib/css-loader/pull/1140/graphs/tree.svg?width=650&height=150&src=pr&token=DlN3OQ0JnO)](https://codecov.io/gh/webpack-contrib/css-loader/pull/1140?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master    #1140   +/-   ##
=======================================
  Coverage   99.18%   99.18%           
=======================================
  Files          10       10           
  Lines         612      614    +2     
  Branches      188      189    +1     
=======================================
+ Hits          607      609    +2     
  Misses          5        5           
```


| [Impacted Files](https://codecov.io/gh/webpack-contrib/css-loader/pull/1140?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/index.js](https://codecov.io/gh/webpack-contrib/css-loader/pull/1140/diff?src=pr&el=tree#diff-c3JjL2luZGV4Lmpz) | `100.00% <100.00%> (ø)` | |
| [src/utils.js](https://codecov.io/gh/webpack-contrib/css-loader/pull/1140/diff?src=pr&el=tree#diff-c3JjL3V0aWxzLmpz) | `98.00% <100.00%> (+0.01%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/webpack-contrib/css-loader/pull/1140?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/webpack-contrib/css-loader/pull/1140?src=pr&el=footer). Last update [bc7b18d...8a11dd5](https://codecov.io/gh/webpack-contrib/css-loader/pull/1140?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/README.md b/README.md
index 7548eae..d175a8e 100644
--- a/README.md
+++ b/README.md
@@ -1000,6 +1000,33 @@ module.exports = {
 };
 ```
 
+### `icss`
+
+Type: Boolean Default: `true` if `modules` are enabled, false otherwise
+
+Enables/disables handling of the low level "Interoperable CSS" format for declaring
+import and export dependencies between CSS and other languages. ICSS enables
+CSS Module support, and is enabled automatically when `modules` are enabled. It
+can also be enabled independently to allow other loaders to handle processing CSS modules.
+
+**webpack.config.js**
+
+```js
+module.exports = {
+  module: {
+    rules: [
+      {
+        test: /\.css$/i,
+        loader: 'css-loader',
+        options: {
+          icss: true,
+        },
+      },
+    ],
+  },
+};
+```
+
 ### `sourceMap`
 
 Type: `Boolean`
diff --git a/src/index.js b/src/index.js
index 06d3058..a3a68d4 100644
--- a/src/index.js
+++ b/src/index.js
@@ -111,7 +111,7 @@ export default async function loader(content, map, meta) {
   const icssPluginImports = [];
   const icssPluginApi = [];
 
-  if (needUseModulesPlugins) {
+  if (needUseModulesPlugins || options.icss) {
     const icssResolver = this.getResolve({
       mainFields: ['css', 'style', 'main', '...'],
       mainFiles: ['index', '...'],
diff --git a/src/options.json b/src/options.json
index 9629553..a7703f3 100644
--- a/src/options.json
+++ b/src/options.json
@@ -118,6 +118,10 @@
         }
       ]
     },
+    "icss": {
+      "description": "Enables/Disables handling the CSS module interoperable import/export format ((https://github.com/webpack-contrib/css-loader#icss)",
+      "type": "boolean"
+    },
     "sourceMap": {
       "description": "Enables/Disables generation of source maps (https://github.com/webpack-contrib/css-loader#sourcemap).",
       "type": "boolean"
diff --git a/src/utils.js b/src/utils.js
index e14f2db..fdf05f3 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -197,10 +197,12 @@ function getModulesOptions(rawOptions, loaderContext) {
 }
 
 function normalizeOptions(rawOptions, loaderContext) {
+  const modulesOptions = getModulesOptions(rawOptions, loaderContext);
   return {
     url: typeof rawOptions.url === 'undefined' ? true : rawOptions.url,
     import: typeof rawOptions.import === 'undefined' ? true : rawOptions.import,
-    modules: getModulesOptions(rawOptions, loaderContext),
+    modules: modulesOptions,
+    icss: modulesOptions ? true : rawOptions.icss,
     sourceMap:
       typeof rawOptions.sourceMap === 'boolean'
         ? rawOptions.sourceMap


Test patch:
diff --git a/test/__snapshots__/validate-options.test.js.snap b/test/__snapshots__/validate-options.test.js.snap
index c48b0b1..fb72576 100644
--- a/test/__snapshots__/validate-options.test.js.snap
+++ b/test/__snapshots__/validate-options.test.js.snap
@@ -6,6 +6,18 @@ exports[`validate options should throw an error on the "esModule" option with "t
    -> Use the ES modules syntax (https://github.com/webpack-contrib/css-loader#esmodule)."
 `;
 
+exports[`validate options should throw an error on the "icss" option with "1" value 1`] = `
+"Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
+ - options.icss should be a boolean.
+   -> Enables/Disables handling the CSS module interoperable import/export format ((https://github.com/webpack-contrib/css-loader#icss)"
+`;
+
+exports[`validate options should throw an error on the "icss" 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.icss should be a boolean.
+   -> Enables/Disables handling the CSS module interoperable import/export format ((https://github.com/webpack-contrib/css-loader#icss)"
+`;
+
 exports[`validate options should throw an error on the "import" 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.import should be one of these:
@@ -235,49 +247,49 @@ exports[`validate options should throw an error on the "sourceMap" option with "
 exports[`validate options should throw an error on the "unknown" option with "/test/" value 1`] = `
 "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
  - options has an unknown property 'unknown'. These properties are valid:
-   object { url?, import?, modules?, sourceMap?, importLoaders?, esModule? }"
+   object { url?, import?, modules?, icss?, sourceMap?, importLoaders?, esModule? }"
 `;
 
 exports[`validate options should throw an error on the "unknown" option with "[]" value 1`] = `
 "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
  - options has an unknown property 'unknown'. These properties are valid:
-   object { url?, import?, modules?, sourceMap?, importLoaders?, esModule? }"
+   object { url?, import?, modules?, icss?, sourceMap?, importLoaders?, esModule? }"
 `;
 
 exports[`validate options should throw an error on the "unknown" option with "{"foo":"bar"}" value 1`] = `
 "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
  - options has an unknown property 'unknown'. These properties are valid:
-   object { url?, import?, modules?, sourceMap?, importLoaders?, esModule? }"
+   object { url?, import?, modules?, icss?, sourceMap?, importLoaders?, esModule? }"
 `;
 
 exports[`validate options should throw an error on the "unknown" option with "{}" value 1`] = `
 "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
  - options has an unknown property 'unknown'. These properties are valid:
-   object { url?, import?, modules?, sourceMap?, importLoaders?, esModule? }"
+   object { url?, import?, modules?, icss?, sourceMap?, importLoaders?, esModule? }"
 `;
 
 exports[`validate options should throw an error on the "unknown" option with "1" value 1`] = `
 "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
  - options has an unknown property 'unknown'. These properties are valid:
-   object { url?, import?, modules?, sourceMap?, importLoaders?, esModule? }"
+   object { url?, import?, modules?, icss?, sourceMap?, importLoaders?, esModule? }"
 `;
 
 exports[`validate options should throw an error on the "unknown" option with "false" value 1`] = `
 "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
  - options has an unknown property 'unknown'. These properties are valid:
-   object { url?, import?, modules?, sourceMap?, importLoaders?, esModule? }"
+   object { url?, import?, modules?, icss?, sourceMap?, importLoaders?, esModule? }"
 `;
 
 exports[`validate options should throw an error on the "unknown" option with "test" value 1`] = `
 "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
  - options has an unknown property 'unknown'. These properties are valid:
-   object { url?, import?, modules?, sourceMap?, importLoaders?, esModule? }"
+   object { url?, import?, modules?, icss?, sourceMap?, importLoaders?, esModule? }"
 `;
 
 exports[`validate options should throw an error on the "unknown" 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 has an unknown property 'unknown'. These properties are valid:
-   object { url?, import?, modules?, sourceMap?, importLoaders?, esModule? }"
+   object { url?, import?, modules?, icss?, sourceMap?, importLoaders?, esModule? }"
 `;
 
 exports[`validate options should throw an error on the "url" option with "true" value 1`] = `
diff --git a/test/icss.test.js b/test/icss.test.js
index a296330..ff1ba97 100644
--- a/test/icss.test.js
+++ b/test/icss.test.js
@@ -17,7 +17,8 @@ describe('ICSS', () => {
   testCases.forEach((name) => {
     it(`show work with the case "${name}"`, async () => {
       const compiler = getCompiler(`./icss/tests-cases/${name}/source.js`, {
-        modules: 'global',
+        modules: false,
+        icss: true,
       });
       const stats = await compile(compiler);
 
diff --git a/test/validate-options.test.js b/test/validate-options.test.js
index 70a9bad..dd95c0a 100644
--- a/test/validate-options.test.js
+++ b/test/validate-options.test.js
@@ -10,6 +10,10 @@ describe('validate options', () => {
       success: [true, false, () => {}],
       failure: ['true'],
     },
+    icss: {
+      success: [true, false],
+      failure: ['true', 1],
+    },
     modules: {
       success: [
         true,