Skip to content

Commit e9fd9a7

Browse files
authored
feat!: deprecate css.modules in favor of css.requireModuleExtension (#4387)
closes #4376 Since css-loader v3, custom CSS Modules configurations are under the `modules` field. So when a user customizes these configurations, the `modules` feature is automatically enabled for all css files. So we must require the user's explicit consensus or disagreement on whether these rules apply to all CSS files or not.
1 parent 96eac78 commit e9fd9a7

File tree

8 files changed

+172
-11
lines changed

8 files changed

+172
-11
lines changed

docs/config/README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,20 @@ See [the plugin's README](https://github.com/vuejs/vue-cli/blob/dev/packages/%40
247247

248248
### css.modules
249249

250+
Deprecated since v4, please use [`css.requireModuleExtension`](#css-requireModuleExtension) instead.
251+
252+
In v3 this means the opposite of `css.requireModuleExtension`.
253+
254+
### css.requireModuleExtension
255+
250256
- Type: `boolean`
251-
- Default: `false`
257+
- Default: `true`
258+
259+
By default, only files that ends in `*.module.[ext]` are treated as CSS modules. Setting this to `false` will allow you to drop `.module` in the filenames and treat all `*.(css|scss|sass|less|styl(us)?)` files as CSS modules.
252260

253-
By default, only files that ends in `*.module.[ext]` are treated as CSS modules. Setting this to `true` will allow you to drop `.module` in the filenames and treat all `*.(css|scss|sass|less|styl(us)?)` files as CSS modules.
261+
::: tip
262+
If you have customized CSS Modules configurations in `css.loaderOptions.css`, then the `css.requireModuleExtension` field must be explictly configured to `true` or `false`, otherwise we can't be sure whether you want to apply these options to all CSS files or not.
263+
:::
254264

255265
See also: [Working with CSS > CSS Modules](../guide/css.md#css-modules)
256266

docs/guide/css.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,13 @@ import styles from './foo.module.css'
8989
import sassStyles from './foo.module.scss'
9090
```
9191

92-
If you want to drop the `.module` in the filenames, set `css.modules` to `true` in `vue.config.js`:
92+
If you want to drop the `.module` in the filenames, set `css.requireModuleExtension` to `false` in `vue.config.js`:
9393

9494
``` js
9595
// vue.config.js
9696
module.exports = {
9797
css: {
98-
modules: true
98+
requireModuleExtension: false
9999
}
100100
}
101101
```

docs/zh/config/README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,19 @@ module.exports = {
235235

236236
### css.modules
237237

238+
从 v4 起已弃用,请使用[`css.requireModuleExtension`](#css-requireModuleExtension)
239+
在 v3 中,这个选项含义与 `css.requireModuleExtension` 相反。
240+
241+
### css.requireModuleExtension
242+
238243
- Type: `boolean`
239-
- Default: `false`
244+
- Default: `true`
240245

241-
默认情况下,只有 `*.module.[ext]` 结尾的文件才会被视作 CSS Modules 模块。设置为 `true` 后你就可以去掉文件名中的 `.module` 并将所有的 `*.(css|scss|sass|less|styl(us)?)` 文件视为 CSS Modules 模块。
246+
默认情况下,只有 `*.module.[ext]` 结尾的文件才会被视作 CSS Modules 模块。设置为 `false` 后你就可以去掉文件名中的 `.module` 并将所有的 `*.(css|scss|sass|less|styl(us)?)` 文件视为 CSS Modules 模块。
247+
248+
::: tip 提示
249+
如果你在 `css.loaderOptions.css` 里配置了自定义的 CSS Module 选项,则 `css.requireModuleExtension` 必须被显式地指定为 `true` 或者 `false`,否则我们无法确定你是否希望将这些自定义配置应用到所有 CSS 文件中。
250+
:::
242251

243252
更多细节可查阅:[配合 CSS > CSS Modules](../guide/css.md#css-modules)
244253

docs/zh/guide/css.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,13 @@ import styles from './foo.module.css'
8181
import sassStyles from './foo.module.scss'
8282
```
8383

84-
如果你想去掉文件名中的 `.module`,可以设置 `vue.config.js` 中的 `css.modules``true`
84+
如果你想去掉文件名中的 `.module`,可以设置 `vue.config.js` 中的 `css.requireModuleExtension``false`
8585

8686
``` js
8787
// vue.config.js
8888
module.exports = {
8989
css: {
90-
modules: true
90+
requireModuleExtension: false
9191
}
9292
}
9393
```

packages/@vue/cli-service/__tests__/css.spec.js

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
const { logs } = require('@vue/cli-shared-utils')
12
const Service = require('../lib/Service')
23

4+
beforeEach(() => {
5+
logs.warn = []
6+
})
7+
38
const LANGS = ['css', 'sass', 'scss', 'less', 'styl', 'stylus']
49
const extractLoaderPath = require('mini-css-extract-plugin').loader
510

@@ -82,7 +87,7 @@ test('CSS Modules rules', () => {
8287
const config = genConfig({
8388
vue: {
8489
css: {
85-
modules: true
90+
requireModuleExtension: false
8691
}
8792
}
8893
})
@@ -103,6 +108,116 @@ test('CSS Modules rules', () => {
103108
})
104109
})
105110

111+
test('Customized CSS Modules rules', () => {
112+
const userOptions = {
113+
vue: {
114+
css: {
115+
loaderOptions: {
116+
css: {
117+
modules: {
118+
localIdentName: '[folder]-[name]-[local][emoji]'
119+
}
120+
}
121+
}
122+
}
123+
}
124+
}
125+
126+
expect(() => {
127+
genConfig(userOptions)
128+
}).toThrow('`css.requireModuleExtension` is required when custom css modules options provided')
129+
130+
userOptions.vue.css.requireModuleExtension = true
131+
const config = genConfig(userOptions)
132+
133+
LANGS.forEach(lang => {
134+
const expected = {
135+
importLoaders: 1, // no postcss-loader
136+
sourceMap: false,
137+
modules: {
138+
localIdentName: `[folder]-[name]-[local][emoji]`
139+
}
140+
}
141+
// vue-modules rules
142+
expect(findOptions(config, lang, 'css', 0)).toEqual(expected)
143+
// normal-modules rules
144+
expect(findOptions(config, lang, 'css', 2)).toEqual(expected)
145+
// normal rules
146+
expect(findOptions(config, lang, 'css', 3)).not.toEqual(expected)
147+
})
148+
})
149+
150+
test('deprecate `css.modules` option', () => {
151+
const config = genConfig({
152+
vue: {
153+
css: {
154+
modules: true,
155+
loaderOptions: {
156+
css: {
157+
modules: {
158+
localIdentName: '[folder]-[name]-[local][emoji]'
159+
}
160+
}
161+
}
162+
}
163+
}
164+
})
165+
expect(logs.warn.some(([msg]) => msg.match('please use "css.requireModuleExtension" instead'))).toBe(true)
166+
167+
LANGS.forEach(lang => {
168+
const expected = {
169+
importLoaders: 1, // no postcss-loader
170+
sourceMap: false,
171+
modules: {
172+
localIdentName: `[folder]-[name]-[local][emoji]`
173+
}
174+
}
175+
// vue-modules rules
176+
expect(findOptions(config, lang, 'css', 0)).toEqual(expected)
177+
// normal-modules rules
178+
expect(findOptions(config, lang, 'css', 2)).toEqual(expected)
179+
// normal rules
180+
expect(findOptions(config, lang, 'css', 3)).toEqual(expected)
181+
})
182+
})
183+
184+
test('favor `css.requireModuleExtension` over `css.modules`', () => {
185+
const config = genConfig({
186+
vue: {
187+
css: {
188+
requireModuleExtension: false,
189+
modules: false,
190+
191+
loaderOptions: {
192+
css: {
193+
modules: {
194+
localIdentName: '[folder]-[name]-[local][emoji]'
195+
}
196+
}
197+
}
198+
}
199+
}
200+
})
201+
202+
expect(logs.warn.some(([msg]) => msg.match('"css.modules" will be ignored in favor of "css.requireModuleExtension"'))).toBe(true)
203+
204+
LANGS.forEach(lang => {
205+
const expected = {
206+
importLoaders: 1, // no postcss-loader
207+
sourceMap: false,
208+
modules: {
209+
localIdentName: `[folder]-[name]-[local][emoji]`
210+
}
211+
}
212+
// vue-modules rules
213+
expect(findOptions(config, lang, 'css', 0)).toEqual(expected)
214+
// normal-modules rules
215+
expect(findOptions(config, lang, 'css', 2)).toEqual(expected)
216+
// normal rules
217+
expect(findOptions(config, lang, 'css', 3)).toEqual(expected)
218+
})
219+
})
220+
106221
test('css.extract', () => {
107222
const config = genConfig({
108223
vue: {

packages/@vue/cli-service/lib/Service.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,22 @@ module.exports = class Service {
346346
resolvedFrom = 'inline options'
347347
}
348348

349+
350+
if (resolved.css && typeof resolved.css.modules !== 'undefined') {
351+
if (typeof resolved.css.requireModuleExtension !== 'undefined') {
352+
warn(
353+
`You have set both "css.modules" and "css.requireModuleExtension" in ${chalk.bold('vue.config.js')}, ` +
354+
`"css.modules" will be ignored in favor of "css.requireModuleExtension".`
355+
)
356+
} else {
357+
warn(
358+
`"css.modules" option in ${chalk.bold('vue.config.js')} ` +
359+
`is deprecated now, please use "css.requireModuleExtension" instead.`
360+
)
361+
resolved.css.requireModuleExtension = !resolved.css.modules
362+
}
363+
}
364+
349365
// normalize some options
350366
ensureSlash(resolved, 'publicPath')
351367
if (typeof resolved.publicPath === 'string') {

packages/@vue/cli-service/lib/config/css.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ module.exports = (api, rootOptions) => {
2727
loaderOptions = {}
2828
} = rootOptions.css || {}
2929

30+
let { requireModuleExtension } = rootOptions.css || {}
31+
if (typeof requireModuleExtension === 'undefined') {
32+
if (loaderOptions.css && loaderOptions.css.modules) {
33+
throw new Error('`css.requireModuleExtension` is required when custom css modules options provided')
34+
}
35+
requireModuleExtension = true
36+
}
37+
3038
const shouldExtract = extract !== false && !shadowMode
3139
const filename = getAssetPath(
3240
rootOptions,
@@ -91,8 +99,7 @@ module.exports = (api, rootOptions) => {
9199

92100
// rules for normal CSS imports
93101
const normalRule = baseRule.oneOf('normal')
94-
const treatAllAsModules = !!(rootOptions.css && rootOptions.css.modules)
95-
applyLoaders(normalRule, treatAllAsModules)
102+
applyLoaders(normalRule, !requireModuleExtension)
96103

97104
function applyLoaders (rule, isCssModule) {
98105
if (shouldExtract) {
@@ -127,6 +134,8 @@ module.exports = (api, rootOptions) => {
127134
localIdentName: '[name]_[local]_[hash:base64:5]',
128135
...cssLoaderOptions.modules
129136
}
137+
} else {
138+
delete cssLoaderOptions.modules
130139
}
131140

132141
rule

packages/@vue/cli-service/lib/options.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ const schema = createSchema(joi => joi.object({
3333

3434
// css
3535
css: joi.object({
36+
// TODO: deprecate this after joi 16 release
3637
modules: joi.boolean(),
38+
requireModuleExtension: joi.boolean(),
3739
extract: joi.alternatives().try(joi.boolean(), joi.object()),
3840
sourceMap: joi.boolean(),
3941
loaderOptions: joi.object({

0 commit comments

Comments
 (0)