diff --git a/docs/guide/css.md b/docs/guide/css.md index 75bfb199dd..aac1986dbf 100644 --- a/docs/guide/css.md +++ b/docs/guide/css.md @@ -133,8 +133,9 @@ module.exports = { // pass options to sass-loader // @/ is an alias to src/ // so this assumes you have a file named `src/variables.sass` + // Note: this option is named as "data" in sass-loader v7 sass: { - data: `@import "~@/variables.sass"` + prependData: `@import "~@/variables.sass"` }, // by default the `sass` option will apply to both syntaxes // because `scss` syntax is also processed by sass-loader underlyingly @@ -142,7 +143,7 @@ module.exports = { // `scss` syntax requires an semicolon at the end of a statement, while `sass` syntax requires none // in that case, we can target the `scss` syntax separately using the `scss` option scss: { - data: `@import "~@/variables.scss";` + prependData: `@import "~@/variables.scss";` }, // pass Less.js Options to less-loader less:{ diff --git a/docs/zh/guide/css.md b/docs/zh/guide/css.md index 2758e6c0bc..1c43282863 100644 --- a/docs/zh/guide/css.md +++ b/docs/zh/guide/css.md @@ -121,7 +121,8 @@ module.exports = { sass: { // @/ 是 src/ 的别名 // 所以这里假设你有 `src/variables.sass` 这个文件 - data: `@import "~@/variables.sass"` + // 注意:在 sass-loader v7 中,这个选项名是 "data" + prependData: `@import "~@/variables.sass"` }, // 默认情况下 `sass` 选项会同时对 `sass` 和 `scss` 语法同时生效 // 因为 `scss` 语法在内部也是由 sass-loader 处理的 @@ -129,7 +130,7 @@ module.exports = { // `scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号 // 在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置 scss: { - data: `@import "~@/variables.scss";` + prependData: `@import "~@/variables.scss";` }, // 给 less-loader 传递 Less.js 相关选项 less:{ diff --git a/packages/@vue/cli-service/__tests__/css.spec.js b/packages/@vue/cli-service/__tests__/css.spec.js index 7d6d6a6e36..5a6f989308 100644 --- a/packages/@vue/cli-service/__tests__/css.spec.js +++ b/packages/@vue/cli-service/__tests__/css.spec.js @@ -67,7 +67,12 @@ test('default loaders', () => { }) }) // sass indented syntax - expect(findOptions(config, 'sass', 'sass')).toMatchObject({ indentedSyntax: true, sourceMap: false }) + expect(findOptions(config, 'sass', 'sass')).toMatchObject({ + sassOptions: { + indentedSyntax: true + }, + sourceMap: false + }) }) test('production defaults', () => { @@ -296,21 +301,30 @@ test('css-loader options', () => { }) test('css.loaderOptions', () => { - const data = '$env: production;' + const prependData = '$env: production;' const config = genConfig({ vue: { css: { loaderOptions: { sass: { - data + prependData } } } } }) - expect(findOptions(config, 'scss', 'sass')).toMatchObject({ data, sourceMap: false }) - expect(findOptions(config, 'sass', 'sass')).toMatchObject({ data, indentedSyntax: true, sourceMap: false }) + expect(findOptions(config, 'scss', 'sass')).toMatchObject({ + prependData, + sourceMap: false + }) + expect(findOptions(config, 'sass', 'sass')).toMatchObject({ + prependData, + sassOptions: { + indentedSyntax: true + }, + sourceMap: false + }) }) test('scss loaderOptions', () => { @@ -322,24 +336,33 @@ test('scss loaderOptions', () => { css: { loaderOptions: { sass: { - sassData + prependData: sassData }, scss: { - scssData + prependData: scssData } } } } }) - expect(findOptions(config, 'scss', 'sass')).toMatchObject({ scssData, sourceMap: false }) - expect(findOptions(config, 'sass', 'sass')).toMatchObject({ sassData, indentedSyntax: true, sourceMap: false }) + expect(findOptions(config, 'scss', 'sass')).toMatchObject({ + prependData: scssData, + sourceMap: false + }) + expect(findOptions(config, 'sass', 'sass')).toMatchObject({ + prependData: sassData, + sassOptions: { + 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') }) + expect(findOptions(config, 'scss', 'sass')).toMatchObject({ implementation: require('sass') }) + expect(findOptions(config, 'sass', 'sass')).toMatchObject({ implementation: require('sass') }) }) test('skip postcss-loader if no postcss config found', () => { diff --git a/packages/@vue/cli-service/generator/index.js b/packages/@vue/cli-service/generator/index.js index 197416e01c..f169395b81 100644 --- a/packages/@vue/cli-service/generator/index.js +++ b/packages/@vue/cli-service/generator/index.js @@ -29,15 +29,15 @@ module.exports = (api, options) => { const deps = { sass: { sass: '^1.19.0', - 'sass-loader': '^7.1.0' + 'sass-loader': '^8.0.0' }, 'node-sass': { 'node-sass': '^4.12.0', - 'sass-loader': '^7.1.0' + 'sass-loader': '^8.0.0' }, 'dart-sass': { sass: '^1.19.0', - 'sass-loader': '^7.1.0' + 'sass-loader': '^8.0.0' }, less: { 'less': '^3.0.4', diff --git a/packages/@vue/cli-service/lib/config/css.js b/packages/@vue/cli-service/lib/config/css.js index 2133924be4..3265fa36bf 100644 --- a/packages/@vue/cli-service/lib/config/css.js +++ b/packages/@vue/cli-service/lib/config/css.js @@ -1,5 +1,7 @@ const fs = require('fs') const path = require('path') +const semver = require('semver') +const { warn, pauseSpinner, resumeSpinner } = require('@vue/cli-shared-utils') const findExisting = (context, files) => { for (const file of files) { @@ -15,10 +17,23 @@ module.exports = (api, rootOptions) => { const shadowMode = !!process.env.VUE_CLI_CSS_SHADOW_MODE const isProd = process.env.NODE_ENV === 'production' + let sassLoaderVersion + try { + sassLoaderVersion = semver.major(require('sass-loader/package.json').version) + } catch (e) {} + if (sassLoaderVersion < 8) { + pauseSpinner() + warn('A new version of sass-loader is available. Please upgrade for best experience.') + resumeSpinner() + } + const defaultSassLoaderOptions = {} try { defaultSassLoaderOptions.implementation = require('sass') - defaultSassLoaderOptions.fiber = require('fibers') + // since sass-loader 8, fibers will be automatically detected and used + if (sassLoaderVersion < 8) { + defaultSassLoaderOptions.fiber = require('fibers') + } } catch (e) {} const { @@ -175,13 +190,28 @@ module.exports = (api, rootOptions) => { defaultSassLoaderOptions, loaderOptions.scss || loaderOptions.sass )) - createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign( - defaultSassLoaderOptions, - { - indentedSyntax: true - }, - loaderOptions.sass - )) + if (sassLoaderVersion < 8) { + createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign( + defaultSassLoaderOptions, + { + indentedSyntax: true + }, + loaderOptions.sass + )) + } else { + createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign( + defaultSassLoaderOptions, + loaderOptions.sass, + { + sassOptions: Object.assign( + (loaderOptions.sass && loaderOptions.sass.sassOptions) || {}, + { + indentedSyntax: true + } + ) + } + )) + } createCSSRule('less', /\.less$/, 'less-loader', loaderOptions.less) createCSSRule('stylus', /\.styl(us)?$/, 'stylus-loader', Object.assign({ preferPathResolver: 'webpack' diff --git a/packages/@vue/cli-service/package.json b/packages/@vue/cli-service/package.json index a66bf68e89..b5edf63e11 100644 --- a/packages/@vue/cli-service/package.json +++ b/packages/@vue/cli-service/package.json @@ -85,7 +85,7 @@ "devDependencies": { "fibers": ">= 3.1.1 <5.0.0", "sass": "^1.19.0", - "sass-loader": "^7.1.0", + "sass-loader": "^8.0.0", "vue": "^2.6.10", "vue-router": "^3.0.6", "vue-template-compiler": "^2.6.10", diff --git a/packages/@vue/cli-shared-utils/lib/spinner.js b/packages/@vue/cli-shared-utils/lib/spinner.js index 84f44d677e..b8e5abdd0d 100644 --- a/packages/@vue/cli-shared-utils/lib/spinner.js +++ b/packages/@vue/cli-shared-utils/lib/spinner.js @@ -3,6 +3,7 @@ const chalk = require('chalk') const spinner = ora() let lastMsg = null +let isPaused = false exports.logWithSpinner = (symbol, msg) => { if (!msg) { @@ -36,11 +37,17 @@ exports.stopSpinner = (persist) => { } exports.pauseSpinner = () => { - spinner.stop() + if (spinner.isSpinning) { + spinner.stop() + isPaused = true + } } exports.resumeSpinner = () => { - spinner.start() + if (isPaused) { + spinner.start() + isPaused = false + } } exports.failSpinner = (text) => { diff --git a/yarn.lock b/yarn.lock index 5ca04fcd9e..d6a8724561 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4650,15 +4650,14 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" -clone-deep@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" - integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ== +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== dependencies: - for-own "^1.0.0" is-plain-object "^2.0.4" - kind-of "^6.0.0" - shallow-clone "^1.0.0" + kind-of "^6.0.2" + shallow-clone "^3.0.0" clone@2.x, clone@^2.1.1: version "2.1.2" @@ -7375,23 +7374,11 @@ follow-redirects@^1.0.0: dependencies: debug "^3.2.6" -for-in@^0.1.3: - version "0.1.8" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" - integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= - -for-in@^1.0.1, for-in@^1.0.2: +for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= -for-own@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" - integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= - dependencies: - for-in "^1.0.1" - foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" @@ -10265,7 +10252,7 @@ loader-utils@^0.2.16: json5 "^0.5.0" object-assign "^4.0.1" -loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: +loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== @@ -10455,11 +10442,6 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash.tail@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" - integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ= - lodash.template@^4.0.2, lodash.template@^4.4.0, lodash.template@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" @@ -11112,14 +11094,6 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mixin-object@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" - integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= - dependencies: - for-in "^0.1.3" - is-extendable "^0.1.1" - mkdirp-promise@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" @@ -13243,7 +13217,7 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -puppeteer@1.11.0, puppeteer@^1.11.0: +puppeteer@^1.11.0: version "1.11.0" resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.11.0.tgz#63cdbe12b07275cd6e0b94bce41f3fcb20305770" integrity sha512-iG4iMOHixc2EpzqRV+pv7o3GgmU2dNYEMkvKwSaQO/vMZURakwSOn/EYJ6OIRFYOque1qorzIBvrytPIQB3YzQ== @@ -13996,17 +13970,16 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sass-loader@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d" - integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w== +sass-loader@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-8.0.0.tgz#e7b07a3e357f965e6b03dd45b016b0a9746af797" + integrity sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w== dependencies: - clone-deep "^2.0.1" - loader-utils "^1.0.1" - lodash.tail "^4.1.1" - neo-async "^2.5.0" - pify "^3.0.0" - semver "^5.5.0" + clone-deep "^4.0.1" + loader-utils "^1.2.3" + neo-async "^2.6.1" + schema-utils "^2.1.0" + semver "^6.3.0" sass@^1.19.0: version "1.22.9" @@ -14049,6 +14022,14 @@ schema-utils@^2.0.0: ajv "^6.1.0" ajv-keywords "^3.1.0" +schema-utils@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.2.0.tgz#48a065ce219e0cacf4631473159037b2c1ae82da" + integrity sha512-5EwsCNhfFTZvUreQhx/4vVQpJ/lnCAkgoIHLhSpp4ZirE+4hzFvdJi0FMub6hxbFVBJYSpeVVmon+2e7uEGRrA== + dependencies: + ajv "^6.10.2" + ajv-keywords "^3.4.1" + scrollparent@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/scrollparent/-/scrollparent-2.0.1.tgz#715d5b9cc57760fb22bdccc3befb5bfe06b1a317" @@ -14118,7 +14099,7 @@ semver@5.5.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== -semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.2.0: +semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -14232,14 +14213,12 @@ sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -shallow-clone@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571" - integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA== +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== dependencies: - is-extendable "^0.1.1" - kind-of "^5.0.0" - mixin-object "^2.0.1" + kind-of "^6.0.2" shebang-command@^1.2.0: version "1.2.0"