Skip to content

Commit a2c767e

Browse files
committed
fix: minify embedded CSS with extract: false
close #2214
1 parent 8dfa290 commit a2c767e

File tree

4 files changed

+61
-47
lines changed

4 files changed

+61
-47
lines changed

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ test('default loaders', () => {
5454
LANGS.forEach(lang => {
5555
const loader = lang === 'css' ? [] : LOADERS[lang]
5656
expect(findLoaders(config, lang)).toEqual(['vue-style', 'css', 'postcss'].concat(loader))
57+
expect(findOptions(config, lang, 'postcss').plugins).toBeFalsy()
5758
// assert css-loader options
5859
expect(findOptions(config, lang, 'css')).toEqual({
5960
sourceMap: false,
@@ -69,6 +70,7 @@ test('production defaults', () => {
6970
LANGS.forEach(lang => {
7071
const loader = lang === 'css' ? [] : LOADERS[lang]
7172
expect(findLoaders(config, lang)).toEqual([extractLoaderPath, 'css', 'postcss'].concat(loader))
73+
expect(findOptions(config, lang, 'postcss').plugins).toBeFalsy()
7274
expect(findOptions(config, lang, 'css')).toEqual({
7375
sourceMap: false,
7476
importLoaders: 2
@@ -109,7 +111,30 @@ test('css.extract', () => {
109111
}
110112
}, 'production')
111113
LANGS.forEach(lang => {
112-
expect(findLoaders(config, lang)).not.toContain(extractLoaderPath)
114+
const loader = lang === 'css' ? [] : LOADERS[lang]
115+
// when extract is false in production, even without postcss config,
116+
// an instance of postcss-loader is injected for inline minification.
117+
expect(findLoaders(config, lang)).toEqual(['vue-style', 'css', 'postcss'].concat(loader))
118+
expect(findOptions(config, lang, 'css').importLoaders).toBe(2)
119+
expect(findOptions(config, lang, 'postcss').plugins).toBeTruthy()
120+
})
121+
122+
const config2 = genConfig({
123+
postcss: {},
124+
vue: {
125+
css: {
126+
extract: false
127+
}
128+
}
129+
}, 'production')
130+
LANGS.forEach(lang => {
131+
const loader = lang === 'css' ? [] : LOADERS[lang]
132+
// if postcss config is present, two postcss-loaders will be used becasue it
133+
// does not support mixing config files with loader options.
134+
expect(findLoaders(config2, lang)).toEqual(['vue-style', 'css', 'postcss', 'postcss'].concat(loader))
135+
expect(findOptions(config2, lang, 'css').importLoaders).toBe(3)
136+
// minification loader should be injected before the user-facing postcss-loader
137+
expect(findOptions(config2, lang, 'postcss').plugins).toBeTruthy()
113138
})
114139
})
115140

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

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,20 @@ module.exports = (api, options) => {
5151
'.postcssrc.json'
5252
]))
5353

54+
// if building for production but not extracting CSS, we need to minimize
55+
// the embbeded inline CSS as they will not be going through the optimizing
56+
// plugin.
57+
const needInlineMinification = isProd && !shouldExtract
58+
59+
const cssnanoOptions = {
60+
safe: true,
61+
autoprefixer: { disable: true },
62+
mergeLonghand: false
63+
}
64+
if (options.productionSourceMap && sourceMap) {
65+
cssnanoOptions.map = { inline: false }
66+
}
67+
5468
function createCSSRule (lang, test, loader, options) {
5569
const baseRule = webpackConfig.module.rule(lang).test(test)
5670

@@ -92,7 +106,8 @@ module.exports = (api, options) => {
92106
sourceMap,
93107
importLoaders: (
94108
1 + // stylePostLoader injected by vue-loader
95-
hasPostCSSConfig
109+
(hasPostCSSConfig ? 1 : 0) +
110+
(needInlineMinification ? 1 : 0)
96111
)
97112
}, loaderOptions.css)
98113

@@ -111,6 +126,15 @@ module.exports = (api, options) => {
111126
.loader('css-loader')
112127
.options(cssLoaderOptions)
113128

129+
if (needInlineMinification) {
130+
rule
131+
.use('cssnano')
132+
.loader('postcss-loader')
133+
.options({
134+
plugins: [require('cssnano')(cssnanoOptions)]
135+
})
136+
}
137+
114138
if (hasPostCSSConfig) {
115139
rule
116140
.use('postcss-loader')
@@ -143,24 +167,16 @@ module.exports = (api, options) => {
143167
webpackConfig
144168
.plugin('extract-css')
145169
.use(require('mini-css-extract-plugin'), [extractOptions])
146-
}
147170

148-
if (isProd) {
149-
// optimize CSS (dedupe)
150-
const cssProcessorOptions = {
151-
safe: true,
152-
autoprefixer: { disable: true },
153-
mergeLonghand: false
154-
}
155-
if (options.productionSourceMap && sourceMap) {
156-
cssProcessorOptions.map = { inline: false }
171+
// minify extracted CSS
172+
if (isProd) {
173+
webpackConfig
174+
.plugin('optimize-css')
175+
.use(require('@intervolga/optimize-cssnano-plugin'), [{
176+
sourceMap: options.productionSourceMap && sourceMap,
177+
cssnanoOptions
178+
}])
157179
}
158-
webpackConfig
159-
.plugin('optimize-css')
160-
.use(require('@intervolga/optimize-cssnano-plugin'), [{
161-
sourceMap: options.productionSourceMap && sourceMap,
162-
cssnanoOptions: cssProcessorOptions
163-
}])
164180
}
165181
})
166182
}

packages/@vue/cli-service/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"cliui": "^4.1.0",
3737
"copy-webpack-plugin": "^4.5.2",
3838
"css-loader": "^1.0.0",
39+
"cssnano": "^4.0.0",
3940
"debug": "^3.1.0",
4041
"escape-string-regexp": "^1.0.5",
4142
"file-loader": "^1.1.11",

yarn.lock

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7082,7 +7082,7 @@ jest-util@^23.4.0:
70827082
slash "^1.0.0"
70837083
source-map "^0.6.0"
70847084

7085-
jest-validate@^23.0.0, jest-validate@^23.4.0:
7085+
jest-validate@^23.4.0:
70867086
version "23.4.0"
70877087
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-23.4.0.tgz#d96eede01ef03ac909c009e9c8e455197d48c201"
70887088
dependencies:
@@ -7606,34 +7606,6 @@ linkify-it@^2.0.0:
76067606
dependencies:
76077607
uc.micro "^1.0.1"
76087608

7609-
lint-staged@^7.2.0:
7610-
version "7.2.0"
7611-
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-7.2.0.tgz#bdf4bb7f2f37fe689acfaec9999db288a5b26888"
7612-
dependencies:
7613-
app-root-path "^2.0.1"
7614-
chalk "^2.3.1"
7615-
commander "^2.14.1"
7616-
cosmiconfig "^5.0.2"
7617-
debug "^3.1.0"
7618-
dedent "^0.7.0"
7619-
execa "^0.9.0"
7620-
find-parent-dir "^0.3.0"
7621-
is-glob "^4.0.0"
7622-
is-windows "^1.0.2"
7623-
jest-validate "^23.0.0"
7624-
listr "^0.14.1"
7625-
lodash "^4.17.5"
7626-
log-symbols "^2.2.0"
7627-
micromatch "^3.1.8"
7628-
npm-which "^3.0.1"
7629-
p-map "^1.1.1"
7630-
path-is-inside "^1.0.2"
7631-
pify "^3.0.0"
7632-
please-upgrade-node "^3.0.2"
7633-
staged-git-files "1.1.1"
7634-
string-argv "^0.0.2"
7635-
stringify-object "^3.2.2"
7636-
76377609
lint-staged@^7.2.2:
76387610
version "7.2.2"
76397611
resolved "http://registry.npm.taobao.org/lint-staged/download/lint-staged-7.2.2.tgz#0983d55d497f19f36d11ff2c8242b2f56cc2dd05"

0 commit comments

Comments
 (0)