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

feat: support dart-sass as default sass implementation #3321

Merged
merged 4 commits into from
Jan 28, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions packages/@vue/cli-service/__tests__/css.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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', () => {
Expand Down
47 changes: 47 additions & 0 deletions packages/@vue/cli-service/__tests__/generator.spec.js
Original file line number Diff line number Diff line change
@@ -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('<style lang="scss">')
expect(pkg).toHaveProperty(['devDependencies', 'node-sass'])
})

test('node sass', async () => {
const { pkg, files } = await generateWithPlugin([
{
id: '@vue/cli-service',
apply: require('../generator'),
options: {
cssPreprocessor: 'node-sass'
}
}
])

expect(files['src/App.vue']).toMatch('<style lang="scss">')
expect(pkg).toHaveProperty(['devDependencies', 'node-sass'])
})

test('dart sass', async () => {
const { pkg, files } = await generateWithPlugin([
{
id: '@vue/cli-service',
apply: require('../generator'),
options: {
cssPreprocessor: 'dart-sass'
}
}
])

expect(files['src/App.vue']).toMatch('<style lang="scss">')
expect(pkg).toHaveProperty(['devDependencies', 'sass'])
expect(pkg).toHaveProperty(['devDependencies', 'fibers'])
})
11 changes: 11 additions & 0 deletions packages/@vue/cli-service/__tests__/serve.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,14 @@ test('serve with no public dir', async () => {
}
)
})

test('dart sass', async () => {
const project = await create('test-dart-sass', exports.defaultPreset = {
useConfigFiles: false,
cssPreprocessor: 'dart-sass',
plugins: {}
})

// should build successfully
await project.run('vue-cli-service build')
})
12 changes: 11 additions & 1 deletion packages/@vue/cli-service/generator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,19 @@ module.exports = (api, options) => {

if (options.cssPreprocessor) {
const deps = {
// TODO: remove 'sass' option in v4 or rename 'dart-sass' to 'sass'
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',
sass: '^1.16.0',
'sass-loader': '^7.1.0'
},
less: {
'less': '^3.0.4',
Expand Down
2 changes: 1 addition & 1 deletion packages/@vue/cli-service/generator/template/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default {
<style<%-
rootOptions.cssPreprocessor
? ` lang="${
rootOptions.cssPreprocessor === 'sass'
rootOptions.cssPreprocessor.includes('sass')
? 'scss'
: rootOptions.cssPreprocessor
}"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default {
<style scoped<%-
rootOptions.cssPreprocessor
? ` lang="${
rootOptions.cssPreprocessor === 'sass'
rootOptions.cssPreprocessor.includes('sass')
? 'scss'
: rootOptions.cssPreprocessor
}"`
Expand Down
10 changes: 8 additions & 2 deletions packages/@vue/cli-service/lib/config/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ module.exports = (api, options) => {
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,
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions packages/@vue/cli-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@
"vue-template-compiler": "^2.0.0"
},
"devDependencies": {
"fibers": "^3.1.1",
"sass": "^1.16.1",
"sass-loader": "^7.1.0",
"vue": "^2.5.21",
"vue-router": "^3.0.1",
"vue-template-compiler": "^2.5.21",
Expand Down
3 changes: 2 additions & 1 deletion packages/@vue/cli/lib/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: {}
}

Expand Down
12 changes: 10 additions & 2 deletions packages/@vue/cli/lib/promptModules/cssPreprocessors.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
5 changes: 4 additions & 1 deletion packages/@vue/cli/lib/util/inferRootOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ module.exports = function inferRootOptions (pkg) {
}

// cssPreprocessors
if ('sass-loader' in deps) {
if ('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'
Expand Down
4 changes: 3 additions & 1 deletion packages/@vue/cli/lib/util/injectImportsAndOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ module.exports = function injectImportsAndOptions (source, imports, injections)
}
})
// avoid blank line after the previous import
delete ast.program.body[lastImportIndex].loc
if (lastImportIndex !== -1) {
delete ast.program.body[lastImportIndex].loc
}

const nonDuplicates = i => {
return !importDeclarations.some(node => {
Expand Down
Loading