Skip to content

Commit 02859cf

Browse files
authored
feat: support sass-loader v8 (#4662)
* feat: support sass-loader v8 (cherry picked from commit af17a9b) * fix: fix sassOptions merging for scss syntax in sass-loader v8 (#4631) fixes #4630 (cherry picked from commit ebdb142) * fix: avoid accidentally overriding sass config with scss configs (#4637) (cherry picked from commit e63bf61) * chore: don't warn user for sass-loader version here
1 parent 0b254a3 commit 02859cf

File tree

6 files changed

+97
-32
lines changed

6 files changed

+97
-32
lines changed

docs/guide/css.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,17 @@ module.exports = {
128128
// pass options to sass-loader
129129
// @/ is an alias to src/
130130
// so this assumes you have a file named `src/variables.sass`
131+
// Note: this option is named as "data" in sass-loader v7
131132
sass: {
132-
data: `@import "~@/variables.sass"`
133+
prependData: `@import "~@/variables.sass"`
133134
},
134135
// by default the `sass` option will apply to both syntaxes
135136
// because `scss` syntax is also processed by sass-loader underlyingly
136137
// but when configuring the `data` option
137138
// `scss` syntax requires an semicolon at the end of a statement, while `sass` syntax requires none
138139
// in that case, we can target the `scss` syntax separately using the `scss` option
139140
scss: {
140-
data: `@import "~@/variables.scss";`
141+
prependData: `@import "~@/variables.scss";`
141142
},
142143
// pass Less.js Options to less-loader
143144
less:{

docs/zh/guide/css.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,16 @@ module.exports = {
129129
sass: {
130130
// @/ 是 src/ 的别名
131131
// 所以这里假设你有 `src/variables.sass` 这个文件
132-
data: `@import "~@/variables.sass"`
132+
// 注意:在 sass-loader v7 中,这个选项名是 "data"
133+
prependData: `@import "~@/variables.sass"`
133134
},
134135
// 默认情况下 `sass` 选项会同时对 `sass` 和 `scss` 语法同时生效
135136
// 因为 `scss` 语法在内部也是由 sass-loader 处理的
136137
// 但是在配置 `data` 选项的时候
137138
// `scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号
138139
// 在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置
139140
scss: {
140-
data: `@import "~@/variables.scss";`
141+
prependData: `@import "~@/variables.scss";`
141142
},
142143
// 给 less-loader 传递 Less.js 相关选项
143144
less:{

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

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,12 @@ test('default loaders', () => {
6262
})
6363
})
6464
// sass indented syntax
65-
expect(findOptions(config, 'sass', 'sass')).toMatchObject({ indentedSyntax: true, sourceMap: false })
65+
expect(findOptions(config, 'sass', 'sass')).toMatchObject({
66+
sassOptions: {
67+
indentedSyntax: true
68+
},
69+
sourceMap: false
70+
})
6671
})
6772

6873
test('production defaults', () => {
@@ -180,21 +185,38 @@ test('css-loader options', () => {
180185
})
181186

182187
test('css.loaderOptions', () => {
183-
const data = '$env: production;'
188+
const prependData = '$env: production;'
184189
const config = genConfig({
185190
vue: {
186191
css: {
187192
loaderOptions: {
188193
sass: {
189-
data
194+
prependData,
195+
sassOptions: {
196+
includePaths: ['./src/styles']
197+
}
190198
}
191199
}
192200
}
193201
}
194202
})
195203

196-
expect(findOptions(config, 'scss', 'sass')).toMatchObject({ data, sourceMap: false })
197-
expect(findOptions(config, 'sass', 'sass')).toMatchObject({ data, indentedSyntax: true, sourceMap: false })
204+
expect(findOptions(config, 'scss', 'sass')).toMatchObject({
205+
prependData,
206+
sourceMap: false,
207+
sassOptions: {
208+
includePaths: ['./src/styles']
209+
}
210+
})
211+
expect(findOptions(config, 'scss', 'sass').sassOptions).not.toHaveProperty('indentedSyntax')
212+
expect(findOptions(config, 'sass', 'sass')).toMatchObject({
213+
prependData,
214+
sassOptions: {
215+
indentedSyntax: true,
216+
includePaths: ['./src/styles']
217+
},
218+
sourceMap: false
219+
})
198220
})
199221

200222
test('scss loaderOptions', () => {
@@ -206,24 +228,37 @@ test('scss loaderOptions', () => {
206228
css: {
207229
loaderOptions: {
208230
sass: {
209-
sassData
231+
prependData: sassData
210232
},
211233
scss: {
212-
scssData
234+
prependData: scssData,
235+
webpackImporter: false
213236
}
214237
}
215238
}
216239
}
217240
})
218241

219-
expect(findOptions(config, 'scss', 'sass')).toMatchObject({ scssData, sourceMap: false })
220-
expect(findOptions(config, 'sass', 'sass')).toMatchObject({ sassData, indentedSyntax: true, sourceMap: false })
242+
expect(findOptions(config, 'scss', 'sass')).toMatchObject({
243+
prependData: scssData,
244+
sourceMap: false
245+
})
246+
expect(findOptions(config, 'sass', 'sass')).toMatchObject({
247+
prependData: sassData,
248+
sassOptions: {
249+
indentedSyntax: true
250+
},
251+
sourceMap: false
252+
})
253+
254+
// should not merge scss options into default sass config
255+
expect(findOptions(config, 'sass', 'sass')).not.toHaveProperty('webpackImporter')
221256
})
222257

223258
test('should use dart sass implementation whenever possible', () => {
224259
const config = genConfig()
225-
expect(findOptions(config, 'scss', 'sass')).toMatchObject({ fiber: require('fibers'), implementation: require('sass') })
226-
expect(findOptions(config, 'sass', 'sass')).toMatchObject({ fiber: require('fibers'), implementation: require('sass') })
260+
expect(findOptions(config, 'scss', 'sass')).toMatchObject({ implementation: require('sass') })
261+
expect(findOptions(config, 'sass', 'sass')).toMatchObject({ implementation: require('sass') })
227262
})
228263

229264
test('skip postcss-loader if no postcss config found', () => {

packages/@vue/cli-service/generator/index.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,16 @@ module.exports = (api, options) => {
3737
const deps = {
3838
// TODO: remove 'sass' option in v4 or rename 'dart-sass' to 'sass'
3939
sass: {
40-
'node-sass': '^4.9.0',
41-
'sass-loader': '^7.1.0'
40+
'node-sass': '^4.12.0',
41+
'sass-loader': '^8.0.0'
4242
},
4343
'node-sass': {
44-
'node-sass': '^4.9.0',
45-
'sass-loader': '^7.1.0'
44+
'node-sass': '^4.12.0',
45+
'sass-loader': '^8.0.0'
4646
},
4747
'dart-sass': {
48-
sass: '^1.18.0',
49-
'sass-loader': '^7.1.0'
48+
sass: '^1.19.0',
49+
'sass-loader': '^8.0.0'
5050
},
5151
less: {
5252
'less': '^3.0.4',

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

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const fs = require('fs')
22
const path = require('path')
3+
const semver = require('semver')
34

45
const findExisting = (context, files) => {
56
for (const file of files) {
@@ -15,10 +16,18 @@ module.exports = (api, options) => {
1516
const shadowMode = !!process.env.VUE_CLI_CSS_SHADOW_MODE
1617
const isProd = process.env.NODE_ENV === 'production'
1718

19+
let sassLoaderVersion
20+
try {
21+
sassLoaderVersion = semver.major(require('sass-loader/package.json').version)
22+
} catch (e) {}
23+
1824
const defaultSassLoaderOptions = {}
1925
try {
2026
defaultSassLoaderOptions.implementation = require('sass')
21-
defaultSassLoaderOptions.fiber = require('fibers')
27+
// since sass-loader 8, fibers will be automatically detected and used
28+
if (sassLoaderVersion < 8) {
29+
defaultSassLoaderOptions.fiber = require('fibers')
30+
}
2231
} catch (e) {}
2332

2433
const {
@@ -166,16 +175,35 @@ module.exports = (api, options) => {
166175
createCSSRule('css', /\.css$/)
167176
createCSSRule('postcss', /\.p(ost)?css$/)
168177
createCSSRule('scss', /\.scss$/, 'sass-loader', Object.assign(
178+
{},
169179
defaultSassLoaderOptions,
170180
loaderOptions.scss || loaderOptions.sass
171181
))
172-
createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign(
173-
defaultSassLoaderOptions,
174-
{
175-
indentedSyntax: true
176-
},
177-
loaderOptions.sass
178-
))
182+
if (sassLoaderVersion < 8) {
183+
createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign(
184+
{},
185+
defaultSassLoaderOptions,
186+
{
187+
indentedSyntax: true
188+
},
189+
loaderOptions.sass
190+
))
191+
} else {
192+
createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign(
193+
{},
194+
defaultSassLoaderOptions,
195+
loaderOptions.sass,
196+
{
197+
sassOptions: Object.assign(
198+
{},
199+
loaderOptions.sass && loaderOptions.sass.sassOptions,
200+
{
201+
indentedSyntax: true
202+
}
203+
)
204+
}
205+
))
206+
}
179207
createCSSRule('less', /\.less$/, 'less-loader', loaderOptions.less)
180208
createCSSRule('stylus', /\.styl(us)?$/, 'stylus-loader', Object.assign({
181209
preferPathResolver: 'webpack'

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@
8484
"vue-template-compiler": "^2.0.0"
8585
},
8686
"devDependencies": {
87-
"fibers": "^3.1.1",
88-
"sass": "^1.18.0",
89-
"sass-loader": "^7.1.0",
87+
"fibers": ">= 3.1.1 <5.0.0",
88+
"sass": "^1.19.0",
89+
"sass-loader": "^8.0.0",
9090
"vue": "^2.6.10",
9191
"vue-router": "^3.0.3",
9292
"vue-template-compiler": "^2.6.10",

0 commit comments

Comments
 (0)