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

feat: allow to disable css modules and disable their by default #842

Merged
merged 1 commit into from
Dec 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ It's useful when you, for instance, need to post process the CSS as a string.
|:--:|:--:|:-----:|:----------|
|**[`url`](#url)**|`{Boolean}`|`true`| Enable/Disable `url()` handling|
|**[`import`](#import)** |`{Boolean}`|`true`| Enable/Disable @import handling|
|**[`modules`](#modules)**|`{Boolean}`|`false`|Enable/Disable CSS Modules|
|**[`modules`](#modules)**|`{Boolean\|String}`|`false`|Enable/Disable CSS Modules and setup mode|
|**[`localIdentName`](#localidentname)**|`{String}`|`[hash:base64]`|Configure the generated ident|
|**[`sourceMap`](#sourcemap)**|`{Boolean}`|`false`|Enable/Disable Sourcemaps|
|**[`camelCase`](#camelcase)**|`{Boolean\|String}`|`false`|Export Classnames in CamelCase|
Expand Down Expand Up @@ -129,17 +129,33 @@ To import styles from a node module path, prefix it with a `~`:

### [`modules`](https://github.com/css-modules/css-modules)

The query parameter `modules` enables the **CSS Modules** spec.
The `modules` option enables/disables the **CSS Modules** spec and setup basic behaviour.

This enables local scoped CSS by default. (You can switch it off with `:global(...)` or `:global` for selectors and/or rules.).
|Name|Type|Description|
|:--:|:--:|:----------|
|**`true`**|`{Boolean}`|Enables local scoped CSS by default (use **local** mode by default)|
|**`false`**|`{Boolean}`|Disable the **CSS Modules** spec, all **CSS Modules** features (like `@value`, `:local`, `:global` and `composes`) will not work|
|**`'local'`** |`{String}`|Enables local scoped CSS by default (same as `true` value)|
|**`'global'`**|`{String}`|Enables global scoped CSS by default|

Using `false` value increase performance because we avoid parsing **CSS Modules** features, it will be useful for developers who use vanilla css or use other technologies.

You can read about **modes** below

#### `Scope`
##### `Scope`

Using `local` value requires you to specify `:global` classes.
Using `global` value requires you to specify `:local` classes.

By default CSS exports all classnames into a global selector scope. Styles can be locally scoped to avoid globally scoping styles.
You can find more information [here](https://github.com/css-modules/css-modules).

Styles can be locally scoped to avoid globally scoping styles.

The syntax `:local(.className)` can be used to declare `className` in the local scope. The local identifiers are exported by the module.

With `:local` (without brackets) local mode can be switched on for this selector. `:global(.className)` can be used to declare an explicit global selector. With `:global` (without brackets) global mode can be switched on for this selector.
With `:local` (without brackets) local mode can be switched on for this selector.
The `:global(.className)` nocation can be used to declare an explicit global selector.
With `:global` (without brackets) global mode can be switched on for this selector.

The loader replaces local selectors with unique identifiers. The chosen unique identifiers are exported by the module.

Expand Down Expand Up @@ -177,7 +193,7 @@ file.png => ./file.png

You can use `:local(#someId)`, but this is not recommended. Use classes instead of ids.

#### `Composing`
##### `Composing`

When declaring a local classname you can compose a local class from another local classname.

Expand Down Expand Up @@ -213,7 +229,7 @@ exports.locals = {
}
```

#### `Importing`
##### `Importing`

To import a local classname from another module.

Expand Down Expand Up @@ -282,7 +298,7 @@ You can also specify the absolute path to your custom `getLocalIdent` function t

To include source maps set the `sourceMap` option.

I.e. the extract-text-webpack-plugin can handle them.
I.e. the `mini-css-extract-plugin` can handle them.

They are not enabled by default because they expose a runtime overhead and increase in bundle size (JS source maps do not). In addition to that relative paths are buggy and you need to use an absolute public path which includes the server URL.

Expand Down
80 changes: 46 additions & 34 deletions lib/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,43 +62,55 @@ module.exports = function loader(content, map, meta) {

const resolveImport = options.import !== false;
const resolveUrl = options.url !== false;
const loaderContext = this;

const plugins = [
modulesValues,
localByDefault({
mode: options.modules ? 'local' : 'global',
rewriteUrl(global, url) {
if (resolveUrl) {
// eslint-disable-next-line no-param-reassign
url = url.trim();

if (!url.replace(/\s/g, '').length || !isUrlRequest(url)) {
return url;
}

if (global) {
return urlToRequest(url);
const plugins = [];

if (options.modules) {
const loaderContext = this;
const mode =
typeof options.modules === 'boolean' ? 'local' : options.modules;

plugins.push(
modulesValues,
localByDefault({
mode,
rewriteUrl(global, url) {
if (resolveUrl) {
// eslint-disable-next-line no-param-reassign
url = url.trim();

if (!url.replace(/\s/g, '').length || !isUrlRequest(url)) {
return url;
}

if (global) {
return urlToRequest(url);
}
}
}

return url;
},
}),
extractImports(),
modulesScope({
generateScopedName: function generateScopedName(exportName) {
const localIdentName = options.localIdentName || '[hash:base64]';
const customGetLocalIdent = options.getLocalIdent || getLocalIdent;

return customGetLocalIdent(loaderContext, localIdentName, exportName, {
regExp: options.localIdentRegExp,
hashPrefix: options.hashPrefix || '',
context: options.context,
});
},
}),
];
return url;
},
}),
extractImports(),
modulesScope({
generateScopedName: function generateScopedName(exportName) {
const localIdentName = options.localIdentName || '[hash:base64]';
const customGetLocalIdent = options.getLocalIdent || getLocalIdent;

return customGetLocalIdent(
loaderContext,
localIdentName,
exportName,
{
regExp: options.localIdentRegExp,
hashPrefix: options.hashPrefix || '',
context: options.context,
}
);
},
})
);
}

if (resolveImport) {
plugins.push(importParser());
Expand Down
150 changes: 142 additions & 8 deletions test/__snapshots__/import-option.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,8 +1,67 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`import option false and modules false: errors 1`] = `Array []`;
exports[`import option false and modules \`false\`: errors 1`] = `Array []`;

exports[`import option false and modules false: module (evaluated) 1`] = `
exports[`import option false and modules \`false\`: module (evaluated) 1`] = `
Array [
Array [
1,
"@import url(test-other.css) (min-width: 100px);

@value def from './values.css';
@value other from './values.css';
@value other from './values.css';
@value something from './something.css';
@value foo: blue;
@value bar: block;

.ghi {
color: def;
}

.class {
color: foo;
}

.other {
display: bar;
}

.other-other {
width: something;
}

.green {
color: other;
}

.foo {
prop: def;
duplicate: other;
}
",
"",
],
]
`;

exports[`import option false and modules \`false\`: module 1`] = `
"exports = module.exports = require(\\"../../../lib/runtime/api.js\\")(false);
// imports


// module
exports.push([module.id, \\"@import url(test-other.css) (min-width: 100px);\\\\n\\\\n@value def from './values.css';\\\\n@value other from './values.css';\\\\n@value other from './values.css';\\\\n@value something from './something.css';\\\\n@value foo: blue;\\\\n@value bar: block;\\\\n\\\\n.ghi {\\\\n color: def;\\\\n}\\\\n\\\\n.class {\\\\n color: foo;\\\\n}\\\\n\\\\n.other {\\\\n display: bar;\\\\n}\\\\n\\\\n.other-other {\\\\n width: something;\\\\n}\\\\n\\\\n.green {\\\\n color: other;\\\\n}\\\\n\\\\n.foo {\\\\n prop: def;\\\\n duplicate: other;\\\\n}\\\\n\\", \\"\\"]);

// exports
"
`;

exports[`import option false and modules \`false\`: warnings 1`] = `Array []`;

exports[`import option false and modules \`global\`: errors 1`] = `Array []`;

exports[`import option false and modules \`global\`: module (evaluated) 1`] = `
Array [
Array [
2,
Expand Down Expand Up @@ -50,7 +109,7 @@ Array [
]
`;

exports[`import option false and modules false: module 1`] = `
exports[`import option false and modules \`global\`: module 1`] = `
"exports = module.exports = require(\\"../../../lib/runtime/api.js\\")(false);
// imports
exports.i(require(\\"-!../../../index.js??ref--4-0!./values.css\\"), \\"\\");
Expand All @@ -69,11 +128,86 @@ exports.locals = {
};"
`;

exports[`import option false and modules false: warnings 1`] = `Array []`;
exports[`import option false and modules \`global\`: warnings 1`] = `Array []`;

exports[`import option false and modules \`local\`: errors 1`] = `Array []`;

exports[`import option false and modules \`local\`: module (evaluated) 1`] = `
Array [
Array [
2,
"
",
"",
],
Array [
3,
"
",
"",
],
Array [
1,
"@import url(test-other.css) (min-width: 100px);

._3r49KZIIAltPknAjdNVZ-7 {
color: red;
}

._4o0o5eKzoeDOSI0_cR8mr {
color: blue;
}

._2wLXKM9pRjt1oRYvf0Wo3Q {
display: block;
}

._1RBgqC8j3f4iU6k-ocmIG7 {
width: 2112moon;
}

._1lCIckG6C8tRZjGNDsAPWr {
color: green;
}

._1YL4f0i_603GTMRC_pnsP5 {
prop: red;
duplicate: green;
}
",
"",
],
]
`;

exports[`import option false and modules \`local\`: module 1`] = `
"exports = module.exports = require(\\"../../../lib/runtime/api.js\\")(false);
// imports
exports.i(require(\\"-!../../../index.js??ref--4-0!./values.css\\"), \\"\\");
exports.i(require(\\"-!../../../index.js??ref--4-0!./something.css\\"), \\"\\");

// module
exports.push([module.id, \\"@import url(test-other.css) (min-width: 100px);\\\\n\\\\n._3r49KZIIAltPknAjdNVZ-7 {\\\\n color: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\";\\\\n}\\\\n\\\\n._4o0o5eKzoeDOSI0_cR8mr {\\\\n color: blue;\\\\n}\\\\n\\\\n._2wLXKM9pRjt1oRYvf0Wo3Q {\\\\n display: block;\\\\n}\\\\n\\\\n._1RBgqC8j3f4iU6k-ocmIG7 {\\\\n width: \\" + require(\\"-!../../../index.js??ref--4-0!./something.css\\").locals[\\"something\\"] + \\";\\\\n}\\\\n\\\\n._1lCIckG6C8tRZjGNDsAPWr {\\\\n color: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"other\\"] + \\";\\\\n}\\\\n\\\\n._1YL4f0i_603GTMRC_pnsP5 {\\\\n prop: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\";\\\\n duplicate: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"other\\"] + \\";\\\\n}\\\\n\\", \\"\\"]);

// exports
exports.locals = {
\\"def\\": \\"\\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\"\\",
\\"other\\": \\"_2wLXKM9pRjt1oRYvf0Wo3Q\\",
\\"something\\": \\"\\" + require(\\"-!../../../index.js??ref--4-0!./something.css\\").locals[\\"something\\"] + \\"\\",
\\"foo\\": \\"_1YL4f0i_603GTMRC_pnsP5\\",
\\"bar\\": \\"block\\",
\\"ghi\\": \\"_3r49KZIIAltPknAjdNVZ-7\\",
\\"class\\": \\"_4o0o5eKzoeDOSI0_cR8mr\\",
\\"other-other\\": \\"_1RBgqC8j3f4iU6k-ocmIG7\\",
\\"green\\": \\"_1lCIckG6C8tRZjGNDsAPWr\\"
};"
`;

exports[`import option false and modules \`local\`: warnings 1`] = `Array []`;

exports[`import option false and modules true: errors 1`] = `Array []`;
exports[`import option false and modules \`true\`: errors 1`] = `Array []`;

exports[`import option false and modules true: module (evaluated) 1`] = `
exports[`import option false and modules \`true\`: module (evaluated) 1`] = `
Array [
Array [
2,
Expand Down Expand Up @@ -121,7 +255,7 @@ Array [
]
`;

exports[`import option false and modules true: module 1`] = `
exports[`import option false and modules \`true\`: module 1`] = `
"exports = module.exports = require(\\"../../../lib/runtime/api.js\\")(false);
// imports
exports.i(require(\\"-!../../../index.js??ref--4-0!./values.css\\"), \\"\\");
Expand All @@ -144,7 +278,7 @@ exports.locals = {
};"
`;

exports[`import option false and modules true: warnings 1`] = `Array []`;
exports[`import option false and modules \`true\`: warnings 1`] = `Array []`;

exports[`import option false: errors 1`] = `Array []`;

Expand Down
8 changes: 4 additions & 4 deletions test/__snapshots__/loader.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -485,19 +485,19 @@ h1,h2,h3,h4,h5,h6 {
}

main.hero, .hero.main {
background-image: img1x.png;
background-image: url(/webpack/public/path/img1x.png);
}

@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {

main.hero, .hero.main {
background-image: img2x.png;
background-image: url(/webpack/public/path/img2x.png);
}
}

main.hero, .hero.main {
background-image: -webkit-image-set(url(/webpack/public/path/img1x.png) 1x, url(/webpack/public/path/img2x.png) 2x);
background-image: image-set(\\"img1x.png\\" 1x, \\"img2x.png\\" 2x);
background-image: image-set(url(/webpack/public/path/img1x.png) 1x, url(/webpack/public/path/img2x.png) 2x);
}

a {
Expand All @@ -520,7 +520,7 @@ exports = module.exports = require(\\"../../../lib/runtime/api.js\\")(false);


// module
exports.push([module.id, \\":root {\\\\n --fontSize: 1rem;\\\\n --mainColor: rgba(18,52,86,0.47059);\\\\n --secondaryColor: rgba(102, 51, 153, 0.9);\\\\n}\\\\n\\\\nhtml {\\\\n overflow-x: hidden;\\\\n overflow-y: auto;\\\\n overflow: hidden auto;\\\\n}\\\\n\\\\n@media (max-width: 50rem) {\\\\n body {\\\\n color: rgba(18,52,86,0.47059);\\\\n color: var(--mainColor);\\\\n font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;\\\\n font-size: 1rem;\\\\n font-size: var(--fontSize);\\\\n line-height: calc(1rem * 1.5);\\\\n line-height: calc(var(--fontSize) * 1.5);\\\\n word-wrap: break-word;\\\\n padding-left: calc(1rem / 2 + 1px);\\\\n padding-right: calc(1rem / 2 + 1px);\\\\n padding-left: calc(var(--fontSize) / 2 + 1px);\\\\n padding-right: calc(var(--fontSize) / 2 + 1px);\\\\n }\\\\n}\\\\n\\\\nh1,h2,h3,h4,h5,h6 {\\\\n margin-top: 0;\\\\n margin-bottom: 0;\\\\n}\\\\n\\\\nmain.hero, .hero.main {\\\\n background-image: img1x.png;\\\\n}\\\\n\\\\n@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {\\\\n\\\\nmain.hero, .hero.main {\\\\n background-image: img2x.png;\\\\n}\\\\n}\\\\n\\\\nmain.hero, .hero.main {\\\\n background-image: -webkit-image-set(url(\\" + escape(require(\\"./img1x.png\\")) + \\") 1x, url(\\" + escape(require(\\"./img2x.png\\")) + \\") 2x);\\\\n background-image: image-set(\\\\\\"img1x.png\\\\\\" 1x, \\\\\\"img2x.png\\\\\\" 2x);\\\\n}\\\\n\\\\na {\\\\n color: rgba(0, 0, 255, 0.9)\\\\n}\\\\n\\\\na:hover {\\\\n color: #639;\\\\n }\\\\n\\", \\"\\"]);
exports.push([module.id, \\":root {\\\\n --fontSize: 1rem;\\\\n --mainColor: rgba(18,52,86,0.47059);\\\\n --secondaryColor: rgba(102, 51, 153, 0.9);\\\\n}\\\\n\\\\nhtml {\\\\n overflow-x: hidden;\\\\n overflow-y: auto;\\\\n overflow: hidden auto;\\\\n}\\\\n\\\\n@media (max-width: 50rem) {\\\\n body {\\\\n color: rgba(18,52,86,0.47059);\\\\n color: var(--mainColor);\\\\n font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;\\\\n font-size: 1rem;\\\\n font-size: var(--fontSize);\\\\n line-height: calc(1rem * 1.5);\\\\n line-height: calc(var(--fontSize) * 1.5);\\\\n word-wrap: break-word;\\\\n padding-left: calc(1rem / 2 + 1px);\\\\n padding-right: calc(1rem / 2 + 1px);\\\\n padding-left: calc(var(--fontSize) / 2 + 1px);\\\\n padding-right: calc(var(--fontSize) / 2 + 1px);\\\\n }\\\\n}\\\\n\\\\nh1,h2,h3,h4,h5,h6 {\\\\n margin-top: 0;\\\\n margin-bottom: 0;\\\\n}\\\\n\\\\nmain.hero, .hero.main {\\\\n background-image: url(\\" + escape(require(\\"./img1x.png\\")) + \\");\\\\n}\\\\n\\\\n@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {\\\\n\\\\nmain.hero, .hero.main {\\\\n background-image: url(\\" + escape(require(\\"./img2x.png\\")) + \\");\\\\n}\\\\n}\\\\n\\\\nmain.hero, .hero.main {\\\\n background-image: -webkit-image-set(url(\\" + escape(require(\\"./img1x.png\\")) + \\") 1x, url(\\" + escape(require(\\"./img2x.png\\")) + \\") 2x);\\\\n background-image: image-set(url(\\" + escape(require(\\"./img1x.png\\")) + \\") 1x, url(\\" + escape(require(\\"./img2x.png\\")) + \\") 2x);\\\\n}\\\\n\\\\na {\\\\n color: rgba(0, 0, 255, 0.9)\\\\n}\\\\n\\\\na:hover {\\\\n color: #639;\\\\n }\\\\n\\", \\"\\"]);

// exports
"
Expand Down
Loading