Skip to content

Commit

Permalink
feat!: deprecate css.modules in favor of `css.requireModuleExtensio…
Browse files Browse the repository at this point in the history
…n` (vuejs#4387)

closes vuejs#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.
  • Loading branch information
haoqunjiang authored Aug 2, 2019
1 parent 96eac78 commit e9fd9a7
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 11 deletions.
14 changes: 12 additions & 2 deletions docs/config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,20 @@ See [the plugin's README](https://github.com/vuejs/vue-cli/blob/dev/packages/%40

### css.modules

Deprecated since v4, please use [`css.requireModuleExtension`](#css-requireModuleExtension) instead.

In v3 this means the opposite of `css.requireModuleExtension`.

### css.requireModuleExtension

- Type: `boolean`
- Default: `false`
- Default: `true`

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.

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.
::: tip
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.
:::

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

Expand Down
4 changes: 2 additions & 2 deletions docs/guide/css.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,13 @@ import styles from './foo.module.css'
import sassStyles from './foo.module.scss'
```

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

``` js
// vue.config.js
module.exports = {
css: {
modules: true
requireModuleExtension: false
}
}
```
Expand Down
13 changes: 11 additions & 2 deletions docs/zh/config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,19 @@ module.exports = {

### css.modules

从 v4 起已弃用,请使用[`css.requireModuleExtension`](#css-requireModuleExtension)
在 v3 中,这个选项含义与 `css.requireModuleExtension` 相反。

### css.requireModuleExtension

- Type: `boolean`
- Default: `false`
- Default: `true`

默认情况下,只有 `*.module.[ext]` 结尾的文件才会被视作 CSS Modules 模块。设置为 `true` 后你就可以去掉文件名中的 `.module` 并将所有的 `*.(css|scss|sass|less|styl(us)?)` 文件视为 CSS Modules 模块。
默认情况下,只有 `*.module.[ext]` 结尾的文件才会被视作 CSS Modules 模块。设置为 `false` 后你就可以去掉文件名中的 `.module` 并将所有的 `*.(css|scss|sass|less|styl(us)?)` 文件视为 CSS Modules 模块。

::: tip 提示
如果你在 `css.loaderOptions.css` 里配置了自定义的 CSS Module 选项,则 `css.requireModuleExtension` 必须被显式地指定为 `true` 或者 `false`,否则我们无法确定你是否希望将这些自定义配置应用到所有 CSS 文件中。
:::

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

Expand Down
4 changes: 2 additions & 2 deletions docs/zh/guide/css.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ import styles from './foo.module.css'
import sassStyles from './foo.module.scss'
```

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

``` js
// vue.config.js
module.exports = {
css: {
modules: true
requireModuleExtension: false
}
}
```
Expand Down
117 changes: 116 additions & 1 deletion packages/@vue/cli-service/__tests__/css.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
const { logs } = require('@vue/cli-shared-utils')
const Service = require('../lib/Service')

beforeEach(() => {
logs.warn = []
})

const LANGS = ['css', 'sass', 'scss', 'less', 'styl', 'stylus']
const extractLoaderPath = require('mini-css-extract-plugin').loader

Expand Down Expand Up @@ -82,7 +87,7 @@ test('CSS Modules rules', () => {
const config = genConfig({
vue: {
css: {
modules: true
requireModuleExtension: false
}
}
})
Expand All @@ -103,6 +108,116 @@ test('CSS Modules rules', () => {
})
})

test('Customized CSS Modules rules', () => {
const userOptions = {
vue: {
css: {
loaderOptions: {
css: {
modules: {
localIdentName: '[folder]-[name]-[local][emoji]'
}
}
}
}
}
}

expect(() => {
genConfig(userOptions)
}).toThrow('`css.requireModuleExtension` is required when custom css modules options provided')

userOptions.vue.css.requireModuleExtension = true
const config = genConfig(userOptions)

LANGS.forEach(lang => {
const expected = {
importLoaders: 1, // no postcss-loader
sourceMap: false,
modules: {
localIdentName: `[folder]-[name]-[local][emoji]`
}
}
// vue-modules rules
expect(findOptions(config, lang, 'css', 0)).toEqual(expected)
// normal-modules rules
expect(findOptions(config, lang, 'css', 2)).toEqual(expected)
// normal rules
expect(findOptions(config, lang, 'css', 3)).not.toEqual(expected)
})
})

test('deprecate `css.modules` option', () => {
const config = genConfig({
vue: {
css: {
modules: true,
loaderOptions: {
css: {
modules: {
localIdentName: '[folder]-[name]-[local][emoji]'
}
}
}
}
}
})
expect(logs.warn.some(([msg]) => msg.match('please use "css.requireModuleExtension" instead'))).toBe(true)

LANGS.forEach(lang => {
const expected = {
importLoaders: 1, // no postcss-loader
sourceMap: false,
modules: {
localIdentName: `[folder]-[name]-[local][emoji]`
}
}
// vue-modules rules
expect(findOptions(config, lang, 'css', 0)).toEqual(expected)
// normal-modules rules
expect(findOptions(config, lang, 'css', 2)).toEqual(expected)
// normal rules
expect(findOptions(config, lang, 'css', 3)).toEqual(expected)
})
})

test('favor `css.requireModuleExtension` over `css.modules`', () => {
const config = genConfig({
vue: {
css: {
requireModuleExtension: false,
modules: false,

loaderOptions: {
css: {
modules: {
localIdentName: '[folder]-[name]-[local][emoji]'
}
}
}
}
}
})

expect(logs.warn.some(([msg]) => msg.match('"css.modules" will be ignored in favor of "css.requireModuleExtension"'))).toBe(true)

LANGS.forEach(lang => {
const expected = {
importLoaders: 1, // no postcss-loader
sourceMap: false,
modules: {
localIdentName: `[folder]-[name]-[local][emoji]`
}
}
// vue-modules rules
expect(findOptions(config, lang, 'css', 0)).toEqual(expected)
// normal-modules rules
expect(findOptions(config, lang, 'css', 2)).toEqual(expected)
// normal rules
expect(findOptions(config, lang, 'css', 3)).toEqual(expected)
})
})

test('css.extract', () => {
const config = genConfig({
vue: {
Expand Down
16 changes: 16 additions & 0 deletions packages/@vue/cli-service/lib/Service.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,22 @@ module.exports = class Service {
resolvedFrom = 'inline options'
}


if (resolved.css && typeof resolved.css.modules !== 'undefined') {
if (typeof resolved.css.requireModuleExtension !== 'undefined') {
warn(
`You have set both "css.modules" and "css.requireModuleExtension" in ${chalk.bold('vue.config.js')}, ` +
`"css.modules" will be ignored in favor of "css.requireModuleExtension".`
)
} else {
warn(
`"css.modules" option in ${chalk.bold('vue.config.js')} ` +
`is deprecated now, please use "css.requireModuleExtension" instead.`
)
resolved.css.requireModuleExtension = !resolved.css.modules
}
}

// normalize some options
ensureSlash(resolved, 'publicPath')
if (typeof resolved.publicPath === 'string') {
Expand Down
13 changes: 11 additions & 2 deletions packages/@vue/cli-service/lib/config/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ module.exports = (api, rootOptions) => {
loaderOptions = {}
} = rootOptions.css || {}

let { requireModuleExtension } = rootOptions.css || {}
if (typeof requireModuleExtension === 'undefined') {
if (loaderOptions.css && loaderOptions.css.modules) {
throw new Error('`css.requireModuleExtension` is required when custom css modules options provided')
}
requireModuleExtension = true
}

const shouldExtract = extract !== false && !shadowMode
const filename = getAssetPath(
rootOptions,
Expand Down Expand Up @@ -91,8 +99,7 @@ module.exports = (api, rootOptions) => {

// rules for normal CSS imports
const normalRule = baseRule.oneOf('normal')
const treatAllAsModules = !!(rootOptions.css && rootOptions.css.modules)
applyLoaders(normalRule, treatAllAsModules)
applyLoaders(normalRule, !requireModuleExtension)

function applyLoaders (rule, isCssModule) {
if (shouldExtract) {
Expand Down Expand Up @@ -127,6 +134,8 @@ module.exports = (api, rootOptions) => {
localIdentName: '[name]_[local]_[hash:base64:5]',
...cssLoaderOptions.modules
}
} else {
delete cssLoaderOptions.modules
}

rule
Expand Down
2 changes: 2 additions & 0 deletions packages/@vue/cli-service/lib/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ const schema = createSchema(joi => joi.object({

// css
css: joi.object({
// TODO: deprecate this after joi 16 release
modules: joi.boolean(),
requireModuleExtension: joi.boolean(),
extract: joi.alternatives().try(joi.boolean(), joi.object()),
sourceMap: joi.boolean(),
loaderOptions: joi.object({
Expand Down

0 comments on commit e9fd9a7

Please sign in to comment.