Skip to content

Commit 9c1e797

Browse files
authored
feat: support dart-sass as default sass implementation (#3321)
1 parent 9029ad1 commit 9c1e797

File tree

13 files changed

+201
-15
lines changed

13 files changed

+201
-15
lines changed

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ test('default loaders', () => {
6262
})
6363
})
6464
// sass indented syntax
65-
expect(findOptions(config, 'sass', 'sass')).toEqual({ indentedSyntax: true, sourceMap: false })
65+
expect(findOptions(config, 'sass', 'sass')).toMatchObject({ indentedSyntax: true, sourceMap: false })
6666
})
6767

6868
test('production defaults', () => {
@@ -193,8 +193,14 @@ test('css.loaderOptions', () => {
193193
}
194194
})
195195

196-
expect(findOptions(config, 'scss', 'sass')).toEqual({ data, sourceMap: false })
197-
expect(findOptions(config, 'sass', 'sass')).toEqual({ data, indentedSyntax: true, sourceMap: false })
196+
expect(findOptions(config, 'scss', 'sass')).toMatchObject({ data, sourceMap: false })
197+
expect(findOptions(config, 'sass', 'sass')).toMatchObject({ data, indentedSyntax: true, sourceMap: false })
198+
})
199+
200+
test('should use dart sass implementation whenever possible', () => {
201+
const config = genConfig()
202+
expect(findOptions(config, 'scss', 'sass')).toMatchObject({ fiber: require('fibers'), implementation: require('sass') })
203+
expect(findOptions(config, 'sass', 'sass')).toMatchObject({ fiber: require('fibers'), implementation: require('sass') })
198204
})
199205

200206
test('skip postcss-loader if no postcss config found', () => {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
const generateWithPlugin = require('@vue/cli-test-utils/generateWithPlugin')
2+
3+
test('node sass (legacy)', async () => {
4+
const { pkg, files } = await generateWithPlugin([
5+
{
6+
id: '@vue/cli-service',
7+
apply: require('../generator'),
8+
options: {
9+
cssPreprocessor: 'sass'
10+
}
11+
}
12+
])
13+
14+
expect(files['src/App.vue']).toMatch('<style lang="scss">')
15+
expect(pkg).toHaveProperty(['devDependencies', 'node-sass'])
16+
})
17+
18+
test('node sass', async () => {
19+
const { pkg, files } = await generateWithPlugin([
20+
{
21+
id: '@vue/cli-service',
22+
apply: require('../generator'),
23+
options: {
24+
cssPreprocessor: 'node-sass'
25+
}
26+
}
27+
])
28+
29+
expect(files['src/App.vue']).toMatch('<style lang="scss">')
30+
expect(pkg).toHaveProperty(['devDependencies', 'node-sass'])
31+
})
32+
33+
test('dart sass', async () => {
34+
const { pkg, files } = await generateWithPlugin([
35+
{
36+
id: '@vue/cli-service',
37+
apply: require('../generator'),
38+
options: {
39+
cssPreprocessor: 'dart-sass'
40+
}
41+
}
42+
])
43+
44+
expect(files['src/App.vue']).toMatch('<style lang="scss">')
45+
expect(pkg).toHaveProperty(['devDependencies', 'sass'])
46+
expect(pkg).toHaveProperty(['devDependencies', 'fibers'])
47+
})

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,14 @@ test('serve with no public dir', async () => {
9393
}
9494
)
9595
})
96+
97+
test('dart sass', async () => {
98+
const project = await create('test-dart-sass', exports.defaultPreset = {
99+
useConfigFiles: false,
100+
cssPreprocessor: 'dart-sass',
101+
plugins: {}
102+
})
103+
104+
// should build successfully
105+
await project.run('vue-cli-service build')
106+
})

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,19 @@ module.exports = (api, options) => {
3636

3737
if (options.cssPreprocessor) {
3838
const deps = {
39+
// TODO: remove 'sass' option in v4 or rename 'dart-sass' to 'sass'
3940
sass: {
4041
'node-sass': '^4.9.0',
41-
'sass-loader': '^7.0.1'
42+
'sass-loader': '^7.1.0'
43+
},
44+
'node-sass': {
45+
'node-sass': '^4.9.0',
46+
'sass-loader': '^7.1.0'
47+
},
48+
'dart-sass': {
49+
fibers: '^3.1.1',
50+
sass: '^1.16.0',
51+
'sass-loader': '^7.1.0'
4252
},
4353
less: {
4454
'less': '^3.0.4',

packages/@vue/cli-service/generator/template/src/App.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export default {
3939
<style<%-
4040
rootOptions.cssPreprocessor
4141
? ` lang="${
42-
rootOptions.cssPreprocessor === 'sass'
42+
rootOptions.cssPreprocessor.includes('sass')
4343
? 'scss'
4444
: rootOptions.cssPreprocessor
4545
}"`

packages/@vue/cli-service/generator/template/src/components/HelloWorld.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default {
4646
<style scoped<%-
4747
rootOptions.cssPreprocessor
4848
? ` lang="${
49-
rootOptions.cssPreprocessor === 'sass'
49+
rootOptions.cssPreprocessor.includes('sass')
5050
? 'scss'
5151
: rootOptions.cssPreprocessor
5252
}"`

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ module.exports = (api, options) => {
1515
const shadowMode = !!process.env.VUE_CLI_CSS_SHADOW_MODE
1616
const isProd = process.env.NODE_ENV === 'production'
1717

18+
const defaultSassLoaderOptions = {}
19+
try {
20+
defaultSassLoaderOptions.implementation = require('sass')
21+
defaultSassLoaderOptions.fiber = require('fibers')
22+
} catch (e) {}
23+
1824
const {
1925
modules = false,
2026
extract = isProd,
@@ -158,8 +164,8 @@ module.exports = (api, options) => {
158164

159165
createCSSRule('css', /\.css$/)
160166
createCSSRule('postcss', /\.p(ost)?css$/)
161-
createCSSRule('scss', /\.scss$/, 'sass-loader', loaderOptions.sass)
162-
createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign({
167+
createCSSRule('scss', /\.scss$/, 'sass-loader', Object.assign(defaultSassLoaderOptions, loaderOptions.sass))
168+
createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign(defaultSassLoaderOptions, {
163169
indentedSyntax: true
164170
}, loaderOptions.sass))
165171
createCSSRule('less', /\.less$/, 'less-loader', loaderOptions.less)

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@
7676
"vue-template-compiler": "^2.0.0"
7777
},
7878
"devDependencies": {
79+
"fibers": "^3.1.1",
80+
"sass": "^1.16.1",
81+
"sass-loader": "^7.1.0",
7982
"vue": "^2.5.21",
8083
"vue-router": "^3.0.1",
8184
"vue-template-compiler": "^2.5.21",

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ const presetSchema = createSchema(joi => joi.object().keys({
1313
router: joi.boolean(),
1414
routerHistoryMode: joi.boolean(),
1515
vuex: joi.boolean(),
16-
cssPreprocessor: joi.string().only(['sass', 'less', 'stylus']),
16+
// TODO: remove 'sass' or make it equivalent to 'dart-sass' in v4
17+
cssPreprocessor: joi.string().only(['sass', 'dart-sass', 'node-sass', 'less', 'stylus']),
1718
plugins: joi.object().required(),
1819
configs: joi.object()
1920
}))

packages/@vue/cli/lib/promptModules/__tests__/cssPreprocessors.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ test('CSS pre-processor ', async () => {
1414
},
1515
{
1616
message: 'Pick a CSS pre-processor',
17-
choices: ['Sass', 'Less', 'Stylus'],
17+
choices: ['Sass/SCSS (with dart-sass)', 'Sass/SCSS (with node-sass)', 'Less', 'Stylus'],
1818
choose: 0
1919
}
2020
]
2121

2222
const expectedOptions = {
23-
cssPreprocessor: 'sass',
23+
cssPreprocessor: 'dart-sass',
2424
plugins: {}
2525
}
2626

packages/@vue/cli/lib/promptModules/cssPreprocessors.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,17 @@ module.exports = cli => {
1515
message: `Pick a CSS pre-processor${process.env.VUE_CLI_API_MODE ? '' : ` (${notice})`}:`,
1616
description: `${notice}.`,
1717
choices: [
18+
// In Vue CLI <= 3.3, the value of Sass option in 'sass' an means 'node-sass'.
19+
// Considering the 'sass' package on NPM is actually for Dart Sass, we renamed it to 'node-sass'.
20+
// In @vue/cli-service there're still codes that accepts 'sass' as an option value, for compatibility reasons,
21+
// and they're meant to be removed in v4.
1822
{
19-
name: 'Sass/SCSS',
20-
value: 'sass'
23+
name: 'Sass/SCSS (with dart-sass)',
24+
value: 'dart-sass'
25+
},
26+
{
27+
name: 'Sass/SCSS (with node-sass)',
28+
value: 'node-sass'
2129
},
2230
{
2331
name: 'Less',

packages/@vue/cli/lib/util/inferRootOptions.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ module.exports = function inferRootOptions (pkg) {
1919
}
2020

2121
// cssPreprocessors
22-
if ('sass-loader' in deps) {
22+
if ('sass' in deps) {
23+
rootOptions.cssPreprocessor = 'dart-sass'
24+
} else if ('node-sass' in deps) {
25+
// TODO: change to 'node-sass' in v4
2326
rootOptions.cssPreprocessor = 'sass'
2427
} else if ('less-loader' in deps) {
2528
rootOptions.cssPreprocessor = 'less'

yarn.lock

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3441,6 +3441,11 @@ big.js@^3.1.3:
34413441
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
34423442
integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==
34433443

3444+
big.js@^5.2.2:
3445+
version "5.2.2"
3446+
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
3447+
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
3448+
34443449
bin-links@^1.1.2:
34453450
version "1.1.2"
34463451
resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-1.1.2.tgz#fb74bd54bae6b7befc6c6221f25322ac830d9757"
@@ -4237,6 +4242,16 @@ cliui@^4.0.0, cliui@^4.1.0:
42374242
strip-ansi "^4.0.0"
42384243
wrap-ansi "^2.0.0"
42394244

4245+
clone-deep@^2.0.1:
4246+
version "2.0.2"
4247+
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713"
4248+
integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==
4249+
dependencies:
4250+
for-own "^1.0.0"
4251+
is-plain-object "^2.0.4"
4252+
kind-of "^6.0.0"
4253+
shallow-clone "^1.0.0"
4254+
42404255
clone@2.x, clone@^2.1.1:
42414256
version "2.1.2"
42424257
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
@@ -5734,7 +5749,7 @@ detect-indent@^5.0.0:
57345749
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d"
57355750
integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50=
57365751

5737-
detect-libc@^1.0.2:
5752+
detect-libc@^1.0.2, detect-libc@^1.0.3:
57385753
version "1.0.3"
57395754
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
57405755
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
@@ -7029,6 +7044,13 @@ fd-slicer@~1.1.0:
70297044
dependencies:
70307045
pend "~1.2.0"
70317046

7047+
fibers@^3.1.1:
7048+
version "3.1.1"
7049+
resolved "https://registry.yarnpkg.com/fibers/-/fibers-3.1.1.tgz#0238902ca938347bd779523692fbeefdf4f688ab"
7050+
integrity sha512-dl3Ukt08rHVQfY8xGD0ODwyjwrRALtaghuqGH2jByYX1wpY+nAnRQjJ6Dbqq0DnVgNVQ9yibObzbF4IlPyiwPw==
7051+
dependencies:
7052+
detect-libc "^1.0.3"
7053+
70327054
figgy-pudding@^3.1.0, figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
70337055
version "3.5.1"
70347056
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
@@ -7278,6 +7300,11 @@ follow-redirects@^1.0.0:
72787300
dependencies:
72797301
debug "=3.1.0"
72807302

7303+
for-in@^0.1.3:
7304+
version "0.1.8"
7305+
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
7306+
integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=
7307+
72817308
for-in@^1.0.1, for-in@^1.0.2:
72827309
version "1.0.2"
72837310
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -7290,6 +7317,13 @@ for-own@^0.1.4:
72907317
dependencies:
72917318
for-in "^1.0.1"
72927319

7320+
for-own@^1.0.0:
7321+
version "1.0.0"
7322+
resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
7323+
integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
7324+
dependencies:
7325+
for-in "^1.0.1"
7326+
72937327
foreach@^2.0.5:
72947328
version "2.0.5"
72957329
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
@@ -9870,6 +9904,13 @@ json5@^0.5.0, json5@^0.5.1:
98709904
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
98719905
integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
98729906

9907+
json5@^1.0.1:
9908+
version "1.0.1"
9909+
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
9910+
integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
9911+
dependencies:
9912+
minimist "^1.2.0"
9913+
98739914
jsonfile@^2.1.0:
98749915
version "2.4.0"
98759916
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8"
@@ -10437,6 +10478,15 @@ loader-utils@^0.2.16:
1043710478
json5 "^0.5.0"
1043810479
object-assign "^4.0.1"
1043910480

10481+
loader-utils@^1.0.1:
10482+
version "1.2.3"
10483+
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
10484+
integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
10485+
dependencies:
10486+
big.js "^5.2.2"
10487+
emojis-list "^2.0.0"
10488+
json5 "^1.0.1"
10489+
1044010490
loader-utils@^1.0.2, loader-utils@^1.1.0:
1044110491
version "1.1.0"
1044210492
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
@@ -10669,6 +10719,11 @@ lodash.sortby@^4.7.0:
1066910719
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
1067010720
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
1067110721

10722+
lodash.tail@^4.1.1:
10723+
version "4.1.1"
10724+
resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
10725+
integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=
10726+
1067210727
lodash.template@^4.0.2, lodash.template@^4.4.0:
1067310728
version "4.4.0"
1067410729
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
@@ -11338,6 +11393,14 @@ mixin-deep@^1.2.0:
1133811393
for-in "^1.0.2"
1133911394
is-extendable "^1.0.1"
1134011395

11396+
mixin-object@^2.0.1:
11397+
version "2.0.1"
11398+
resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e"
11399+
integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=
11400+
dependencies:
11401+
for-in "^0.1.3"
11402+
is-extendable "^0.1.1"
11403+
1134111404
mkdirp@0.3.0:
1134211405
version "0.3.0"
1134311406
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e"
@@ -14413,6 +14476,25 @@ sane@^2.0.0:
1441314476
optionalDependencies:
1441414477
fsevents "^1.2.3"
1441514478

14479+
sass-loader@^7.1.0:
14480+
version "7.1.0"
14481+
resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d"
14482+
integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==
14483+
dependencies:
14484+
clone-deep "^2.0.1"
14485+
loader-utils "^1.0.1"
14486+
lodash.tail "^4.1.1"
14487+
neo-async "^2.5.0"
14488+
pify "^3.0.0"
14489+
semver "^5.5.0"
14490+
14491+
sass@^1.16.0, sass@^1.16.1:
14492+
version "1.16.1"
14493+
resolved "https://registry.yarnpkg.com/sass/-/sass-1.16.1.tgz#3abbb04562c9e3a3ee11c3056956294ed333f6e6"
14494+
integrity sha512-lKoiOI/zsAHrdYAdcWBM0pynYCmK0t7N9OAVjxAoYvo0mDBQmlhM6w+zNuFQYeS6d3VF+7KVWwkX6oWNMJxVag==
14495+
dependencies:
14496+
chokidar "^2.0.0"
14497+
1441614498
sax@0.5.x:
1441714499
version "0.5.8"
1441814500
resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1"
@@ -14616,6 +14698,15 @@ sha.js@^2.4.0, sha.js@^2.4.8:
1461614698
inherits "^2.0.1"
1461714699
safe-buffer "^5.0.1"
1461814700

14701+
shallow-clone@^1.0.0:
14702+
version "1.0.0"
14703+
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571"
14704+
integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==
14705+
dependencies:
14706+
is-extendable "^0.1.1"
14707+
kind-of "^5.0.0"
14708+
mixin-object "^2.0.1"
14709+
1461914710
shebang-command@^1.2.0:
1462014711
version "1.2.0"
1462114712
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"

0 commit comments

Comments
 (0)