Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v3] Support sass-loader v8 #4662

Merged
merged 4 commits into from Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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