Skip to content

Commit

Permalink
feat: support sass-loader v8 (#4662)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
sodatea committed Oct 10, 2019
1 parent 0b254a3 commit 02859cf
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 32 deletions.
5 changes: 3 additions & 2 deletions docs/guide/css.md
Expand Up @@ -128,16 +128,17 @@ 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
// but when configuring the `data` option
// `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:{
Expand Down
5 changes: 3 additions & 2 deletions docs/zh/guide/css.md
Expand Up @@ -129,15 +129,16 @@ 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 处理的
// 但是在配置 `data` 选项的时候
// `scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号
// 在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置
scss: {
data: `@import "~@/variables.scss";`
prependData: `@import "~@/variables.scss";`
},
// 给 less-loader 传递 Less.js 相关选项
less:{
Expand Down
57 changes: 46 additions & 11 deletions packages/@vue/cli-service/__tests__/css.spec.js
Expand Up @@ -62,7 +62,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', () => {
Expand Down Expand Up @@ -180,21 +185,38 @@ test('css-loader options', () => {
})

test('css.loaderOptions', () => {
const data = '$env: production;'
const prependData = '$env: production;'
const config = genConfig({
vue: {
css: {
loaderOptions: {
sass: {
data
prependData,
sassOptions: {
includePaths: ['./src/styles']
}
}
}
}
}
})

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,
sassOptions: {
includePaths: ['./src/styles']
}
})
expect(findOptions(config, 'scss', 'sass').sassOptions).not.toHaveProperty('indentedSyntax')
expect(findOptions(config, 'sass', 'sass')).toMatchObject({
prependData,
sassOptions: {
indentedSyntax: true,
includePaths: ['./src/styles']
},
sourceMap: false
})
})

test('scss loaderOptions', () => {
Expand All @@ -206,24 +228,37 @@ test('scss loaderOptions', () => {
css: {
loaderOptions: {
sass: {
sassData
prependData: sassData
},
scss: {
scssData
prependData: scssData,
webpackImporter: false
}
}
}
}
})

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
})

// should not merge scss options into default sass config
expect(findOptions(config, 'sass', 'sass')).not.toHaveProperty('webpackImporter')
})

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', () => {
Expand Down
12 changes: 6 additions & 6 deletions packages/@vue/cli-service/generator/index.js
Expand Up @@ -37,16 +37,16 @@ module.exports = (api, options) => {
const deps = {
// TODO: remove 'sass' option in v4 or rename 'dart-sass' to 'sass'
sass: {
'node-sass': '^4.9.0',
'sass-loader': '^7.1.0'
'node-sass': '^4.12.0',
'sass-loader': '^8.0.0'
},
'node-sass': {
'node-sass': '^4.9.0',
'sass-loader': '^7.1.0'
'node-sass': '^4.12.0',
'sass-loader': '^8.0.0'
},
'dart-sass': {
sass: '^1.18.0',
'sass-loader': '^7.1.0'
sass: '^1.19.0',
'sass-loader': '^8.0.0'
},
less: {
'less': '^3.0.4',
Expand Down
44 changes: 36 additions & 8 deletions packages/@vue/cli-service/lib/config/css.js
@@ -1,5 +1,6 @@
const fs = require('fs')
const path = require('path')
const semver = require('semver')

const findExisting = (context, files) => {
for (const file of files) {
Expand All @@ -15,10 +16,18 @@ module.exports = (api, options) => {
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) {}

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 {
Expand Down Expand Up @@ -166,16 +175,35 @@ module.exports = (api, options) => {
createCSSRule('css', /\.css$/)
createCSSRule('postcss', /\.p(ost)?css$/)
createCSSRule('scss', /\.scss$/, 'sass-loader', Object.assign(
{},
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'
Expand Down
6 changes: 3 additions & 3 deletions packages/@vue/cli-service/package.json
Expand Up @@ -84,9 +84,9 @@
"vue-template-compiler": "^2.0.0"
},
"devDependencies": {
"fibers": "^3.1.1",
"sass": "^1.18.0",
"sass-loader": "^7.1.0",
"fibers": ">= 3.1.1 <5.0.0",
"sass": "^1.19.0",
"sass-loader": "^8.0.0",
"vue": "^2.6.10",
"vue-router": "^3.0.3",
"vue-template-compiler": "^2.6.10",
Expand Down

0 comments on commit 02859cf

Please sign in to comment.