From fc846bdde5f9258a2fc29fc20e0a3273d7f1ecda Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Fri, 18 Jan 2019 01:48:23 +0800 Subject: [PATCH 1/4] feat: support dart-sass as default sass implementation --- packages/@vue/cli-service/generator/index.js | 12 +++++++++++- .../@vue/cli-service/generator/template/src/App.vue | 2 +- .../generator/template/src/components/HelloWorld.vue | 2 +- packages/@vue/cli-service/lib/config/css.js | 10 ++++++++-- packages/@vue/cli/lib/options.js | 3 ++- .../promptModules/__tests__/cssPreprocessors.spec.js | 4 ++-- .../@vue/cli/lib/promptModules/cssPreprocessors.js | 12 ++++++++++-- packages/@vue/cli/lib/util/inferRootOptions.js | 5 ++++- 8 files changed, 39 insertions(+), 11 deletions(-) diff --git a/packages/@vue/cli-service/generator/index.js b/packages/@vue/cli-service/generator/index.js index c2a58d6a74..4bea0c829c 100644 --- a/packages/@vue/cli-service/generator/index.js +++ b/packages/@vue/cli-service/generator/index.js @@ -36,9 +36,19 @@ module.exports = (api, options) => { if (options.cssPreprocessor) { const deps = { + // TODO: remove 'sass' option in v4 sass: { 'node-sass': '^4.9.0', - 'sass-loader': '^7.0.1' + 'sass-loader': '^7.1.0' + }, + 'node-sass': { + 'node-sass': '^4.9.0', + 'sass-loader': '^7.1.0' + }, + 'dart-sass': { + fibers: '^3.1.1', + 'dart-sass': '^1.16.0', + 'sass-loader': '^7.1.0' }, less: { 'less': '^3.0.4', diff --git a/packages/@vue/cli-service/generator/template/src/App.vue b/packages/@vue/cli-service/generator/template/src/App.vue index ea161ed443..9bc61b1443 100644 --- a/packages/@vue/cli-service/generator/template/src/App.vue +++ b/packages/@vue/cli-service/generator/template/src/App.vue @@ -39,7 +39,7 @@ export default { { const shadowMode = !!process.env.VUE_CLI_CSS_SHADOW_MODE const isProd = process.env.NODE_ENV === 'production' + const defaultSassLoaderOptions = {} + try { + defaultSassLoaderOptions.implementation = require('sass') + defaultSassLoaderOptions.fiber = require('fibers') + } catch (e) {} + const { modules = false, extract = isProd, @@ -158,8 +164,8 @@ module.exports = (api, options) => { createCSSRule('css', /\.css$/) createCSSRule('postcss', /\.p(ost)?css$/) - createCSSRule('scss', /\.scss$/, 'sass-loader', loaderOptions.sass) - createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign({ + createCSSRule('scss', /\.scss$/, 'sass-loader', Object.assign(defaultSassLoaderOptions, loaderOptions.sass)) + createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign(defaultSassLoaderOptions, { indentedSyntax: true }, loaderOptions.sass)) createCSSRule('less', /\.less$/, 'less-loader', loaderOptions.less) diff --git a/packages/@vue/cli/lib/options.js b/packages/@vue/cli/lib/options.js index cacf536eb9..47f6eb0256 100644 --- a/packages/@vue/cli/lib/options.js +++ b/packages/@vue/cli/lib/options.js @@ -13,7 +13,8 @@ const presetSchema = createSchema(joi => joi.object().keys({ router: joi.boolean(), routerHistoryMode: joi.boolean(), vuex: joi.boolean(), - cssPreprocessor: joi.string().only(['sass', 'less', 'stylus']), + // TODO: remove 'sass' or make it equivalent to 'dart-sass' in v4 + cssPreprocessor: joi.string().only(['sass', 'dart-sass', 'node-sass', 'less', 'stylus']), plugins: joi.object().required(), configs: joi.object() })) diff --git a/packages/@vue/cli/lib/promptModules/__tests__/cssPreprocessors.spec.js b/packages/@vue/cli/lib/promptModules/__tests__/cssPreprocessors.spec.js index d006ffd50b..d138eb7c37 100644 --- a/packages/@vue/cli/lib/promptModules/__tests__/cssPreprocessors.spec.js +++ b/packages/@vue/cli/lib/promptModules/__tests__/cssPreprocessors.spec.js @@ -14,13 +14,13 @@ test('CSS pre-processor ', async () => { }, { message: 'Pick a CSS pre-processor', - choices: ['Sass', 'Less', 'Stylus'], + choices: ['Sass/SCSS (with dart-sass)', 'Sass/SCSS (with node-sass)', 'Less', 'Stylus'], choose: 0 } ] const expectedOptions = { - cssPreprocessor: 'sass', + cssPreprocessor: 'dart-sass', plugins: {} } diff --git a/packages/@vue/cli/lib/promptModules/cssPreprocessors.js b/packages/@vue/cli/lib/promptModules/cssPreprocessors.js index 8498efb372..992eebeecc 100644 --- a/packages/@vue/cli/lib/promptModules/cssPreprocessors.js +++ b/packages/@vue/cli/lib/promptModules/cssPreprocessors.js @@ -15,9 +15,17 @@ module.exports = cli => { message: `Pick a CSS pre-processor${process.env.VUE_CLI_API_MODE ? '' : ` (${notice})`}:`, description: `${notice}.`, choices: [ + // In Vue CLI <= 3.3, the value of Sass option in 'sass' an means 'node-sass'. + // Considering the 'sass' package on NPM is actually for Dart Sass, we renamed it to 'node-sass'. + // In @vue/cli-service there're still codes that accepts 'sass' as an option value, for compatibility reasons, + // and they're meant to be removed in v4. { - name: 'Sass/SCSS', - value: 'sass' + name: 'Sass/SCSS (with dart-sass)', + value: 'dart-sass' + }, + { + name: 'Sass/SCSS (with node-sass)', + value: 'node-sass' }, { name: 'Less', diff --git a/packages/@vue/cli/lib/util/inferRootOptions.js b/packages/@vue/cli/lib/util/inferRootOptions.js index 58c5a84285..32a654e8c2 100644 --- a/packages/@vue/cli/lib/util/inferRootOptions.js +++ b/packages/@vue/cli/lib/util/inferRootOptions.js @@ -19,7 +19,10 @@ module.exports = function inferRootOptions (pkg) { } // cssPreprocessors - if ('sass-loader' in deps) { + if ('dart-sass' in deps) { + rootOptions.cssPreprocessor = 'dart-sass' + } else if ('node-sass' in deps) { + // TODO: change to 'node-sass' in v4 rootOptions.cssPreprocessor = 'sass' } else if ('less-loader' in deps) { rootOptions.cssPreprocessor = 'less' From 4cbb6a740c7e5642e538438111e3374dc8d6791c Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Sun, 27 Jan 2019 21:05:45 +0800 Subject: [PATCH 2/4] fix: use correct package name for dart sass --- packages/@vue/cli-service/generator/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@vue/cli-service/generator/index.js b/packages/@vue/cli-service/generator/index.js index 4bea0c829c..6c4c5231df 100644 --- a/packages/@vue/cli-service/generator/index.js +++ b/packages/@vue/cli-service/generator/index.js @@ -36,7 +36,7 @@ module.exports = (api, options) => { if (options.cssPreprocessor) { const deps = { - // TODO: remove 'sass' option in v4 + // TODO: remove 'sass' option in v4 or rename 'dart-sass' to 'sass' sass: { 'node-sass': '^4.9.0', 'sass-loader': '^7.1.0' @@ -47,7 +47,7 @@ module.exports = (api, options) => { }, 'dart-sass': { fibers: '^3.1.1', - 'dart-sass': '^1.16.0', + 'sass': '^1.16.0', 'sass-loader': '^7.1.0' }, less: { From 109b5bacb64d4a26b18f32cb1d0dc24952a57e68 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Mon, 28 Jan 2019 01:22:58 +0800 Subject: [PATCH 3/4] fix: fix typos & style --- packages/@vue/cli-service/generator/index.js | 2 +- packages/@vue/cli/lib/util/inferRootOptions.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@vue/cli-service/generator/index.js b/packages/@vue/cli-service/generator/index.js index 6c4c5231df..12fd6977cb 100644 --- a/packages/@vue/cli-service/generator/index.js +++ b/packages/@vue/cli-service/generator/index.js @@ -47,7 +47,7 @@ module.exports = (api, options) => { }, 'dart-sass': { fibers: '^3.1.1', - 'sass': '^1.16.0', + sass: '^1.16.0', 'sass-loader': '^7.1.0' }, less: { diff --git a/packages/@vue/cli/lib/util/inferRootOptions.js b/packages/@vue/cli/lib/util/inferRootOptions.js index 32a654e8c2..133f3f96d4 100644 --- a/packages/@vue/cli/lib/util/inferRootOptions.js +++ b/packages/@vue/cli/lib/util/inferRootOptions.js @@ -19,7 +19,7 @@ module.exports = function inferRootOptions (pkg) { } // cssPreprocessors - if ('dart-sass' in deps) { + if ('sass' in deps) { rootOptions.cssPreprocessor = 'dart-sass' } else if ('node-sass' in deps) { // TODO: change to 'node-sass' in v4 From 2650a337bcc1e34cb8e27b2205a5a932a7f14a4a Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Mon, 28 Jan 2019 15:42:00 +0800 Subject: [PATCH 4/4] test: add tests for dart sass --- .../@vue/cli-service/__tests__/css.spec.js | 12 ++- .../cli-service/__tests__/generator.spec.js | 47 ++++++++++ .../@vue/cli-service/__tests__/serve.spec.js | 11 +++ packages/@vue/cli-service/package.json | 3 + .../cli/lib/util/injectImportsAndOptions.js | 4 +- yarn.lock | 93 ++++++++++++++++++- 6 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 packages/@vue/cli-service/__tests__/generator.spec.js diff --git a/packages/@vue/cli-service/__tests__/css.spec.js b/packages/@vue/cli-service/__tests__/css.spec.js index ab405e1dee..e257beccfa 100644 --- a/packages/@vue/cli-service/__tests__/css.spec.js +++ b/packages/@vue/cli-service/__tests__/css.spec.js @@ -62,7 +62,7 @@ test('default loaders', () => { }) }) // sass indented syntax - expect(findOptions(config, 'sass', 'sass')).toEqual({ indentedSyntax: true, sourceMap: false }) + expect(findOptions(config, 'sass', 'sass')).toMatchObject({ indentedSyntax: true, sourceMap: false }) }) test('production defaults', () => { @@ -193,8 +193,14 @@ test('css.loaderOptions', () => { } }) - expect(findOptions(config, 'scss', 'sass')).toEqual({ data, sourceMap: false }) - expect(findOptions(config, 'sass', 'sass')).toEqual({ data, indentedSyntax: true, sourceMap: false }) + expect(findOptions(config, 'scss', 'sass')).toMatchObject({ data, sourceMap: false }) + expect(findOptions(config, 'sass', 'sass')).toMatchObject({ data, indentedSyntax: true, sourceMap: false }) +}) + +test('should use dart sass implementation whenever possible', () => { + const config = genConfig() + expect(findOptions(config, 'scss', 'sass')).toMatchObject({ fiber: require('fibers'), implementation: require('sass') }) + expect(findOptions(config, 'sass', 'sass')).toMatchObject({ fiber: require('fibers'), implementation: require('sass') }) }) test('skip postcss-loader if no postcss config found', () => { diff --git a/packages/@vue/cli-service/__tests__/generator.spec.js b/packages/@vue/cli-service/__tests__/generator.spec.js new file mode 100644 index 0000000000..c04283884a --- /dev/null +++ b/packages/@vue/cli-service/__tests__/generator.spec.js @@ -0,0 +1,47 @@ +const generateWithPlugin = require('@vue/cli-test-utils/generateWithPlugin') + +test('node sass (legacy)', async () => { + const { pkg, files } = await generateWithPlugin([ + { + id: '@vue/cli-service', + apply: require('../generator'), + options: { + cssPreprocessor: 'sass' + } + } + ]) + + expect(files['src/App.vue']).toMatch('