feat(compiler-sfc): export dependencies for css and css preprocessors (#1278)

This commit is contained in:
underfin
2020-07-17 00:33:37 +08:00
committed by GitHub
parent ecf872fc95
commit e41d8310de
7 changed files with 145 additions and 21 deletions

View File

@@ -1,9 +1,14 @@
/**
* @jest-environment node
*/
import {
compileStyle,
compileStyleAsync,
SFCStyleCompileOptions
} from '../src/compileStyle'
import { mockWarn } from '@vue/shared'
import path from 'path'
describe('SFC scoped CSS', () => {
mockWarn()
@@ -318,3 +323,20 @@ describe('SFC CSS modules', () => {
expect(result.modules!.bazQux).toBeUndefined()
})
})
describe('SFC style preprocessors', () => {
test('scss @import', () => {
const res = compileStyle({
source: `
@import "./import.scss";
`,
filename: path.resolve(__dirname, './fixture/test.scss'),
id: '',
preprocessLang: 'scss'
})
expect([...res.dependencies]).toStrictEqual([
path.join(__dirname, './fixture/import.scss')
])
})
})

View File

@@ -0,0 +1,3 @@
div {
color: red;
}

View File

@@ -54,6 +54,7 @@
"devDependencies": {
"@types/consolidate": "^0.14.0",
"@types/lru-cache": "^5.1.0",
"pug": "^2.0.4"
"pug": "^2.0.4",
"sass": "^1.26.9"
}
}

View File

@@ -1,4 +1,10 @@
import postcss, { ProcessOptions, LazyResult, Result, ResultMap } from 'postcss'
import postcss, {
ProcessOptions,
LazyResult,
Result,
ResultMap,
ResultMessage
} from 'postcss'
import trimPlugin from './stylePluginTrim'
import scopedPlugin from './stylePluginScoped'
import {
@@ -48,6 +54,7 @@ export interface SFCStyleCompileResults {
rawResult: LazyResult | Result | undefined
errors: Error[]
modules?: Record<string, string>
dependencies: Set<string>
}
export function compileStyle(
@@ -132,12 +139,28 @@ export function doCompileStyle(
let result: LazyResult | undefined
let code: string | undefined
let outMap: ResultMap | undefined
// stylus output include plain css. so need remove the repeat item
const dependencies = new Set(
preProcessedSource ? preProcessedSource.dependencies : []
)
// sass has filename self when provided filename option
dependencies.delete(filename)
const errors: Error[] = []
if (preProcessedSource && preProcessedSource.errors.length) {
errors.push(...preProcessedSource.errors)
}
const recordPlainCssDependencies = (messages: ResultMessage[]) => {
messages.forEach(msg => {
if (msg.type === 'dependency') {
// postcss output path is absolute position path
dependencies.add(msg.file)
}
})
return dependencies
}
try {
result = postcss(plugins).process(source, postCSSOptions)
@@ -149,16 +172,19 @@ export function doCompileStyle(
map: result.map && (result.map.toJSON() as any),
errors,
modules: cssModules,
rawResult: result
rawResult: result,
dependencies: recordPlainCssDependencies(result.messages)
}))
.catch(error => ({
code: '',
map: undefined,
errors: [...errors, error],
rawResult: undefined
rawResult: undefined,
dependencies
}))
}
recordPlainCssDependencies(result.messages)
// force synchronous transform (we know we only have sync plugins)
code = result.css
outMap = result.map
@@ -170,7 +196,8 @@ export function doCompileStyle(
code: code || ``,
map: outMap && (outMap.toJSON() as any),
errors,
rawResult: result
rawResult: result,
dependencies
}
}

View File

@@ -1,4 +1,5 @@
import merge from 'merge-source-map'
import path from 'path'
export interface StylePreprocessor {
render(
@@ -13,6 +14,7 @@ export interface StylePreprocessorResults {
code: string
map?: object
errors: Error[]
dependencies: string[]
}
// .scss/.sass processor
@@ -29,18 +31,20 @@ const scss: StylePreprocessor = {
try {
const result = nodeSass.renderSync(finalOptions)
// sass output path is position path
const dependencies = result.stats.includedFiles
if (map) {
return {
code: result.css.toString(),
map: merge(map, JSON.parse(result.map.toString())),
errors: []
errors: [],
dependencies
}
}
return { code: result.css.toString(), errors: [] }
return { code: result.css.toString(), errors: [], dependencies }
} catch (e) {
return { code: '', errors: [e] }
return { code: '', errors: [e], dependencies: [] }
}
}
}
@@ -75,17 +79,26 @@ const less: StylePreprocessor = {
}
)
if (error) return { code: '', errors: [error] }
if (error) return { code: '', errors: [error], dependencies: [] }
// less output path is relative path
const dependencies = getAbsolutePaths(
result.imports,
path.dirname(options.fileName)
)
if (map) {
return {
code: result.css.toString(),
map: merge(map, result.map),
errors: []
errors: [],
dependencies: dependencies
}
}
return { code: result.css.toString(), errors: [] }
return {
code: result.css.toString(),
errors: [],
dependencies: dependencies
}
}
}
@@ -99,17 +112,23 @@ const styl: StylePreprocessor = {
if (map) ref.set('sourcemap', { inline: false, comment: false })
const result = ref.render()
// stylus output path is relative path
const dependencies = getAbsolutePaths(
ref.deps(),
path.dirname(options.fileName)
)
if (map) {
return {
code: result,
map: merge(map, ref.sourcemap),
errors: []
errors: [],
dependencies
}
}
return { code: result, errors: [] }
return { code: result, errors: [], dependencies }
} catch (e) {
return { code: '', errors: [e] }
return { code: '', errors: [e], dependencies: [] }
}
}
}
@@ -123,3 +142,7 @@ export const processors: Record<PreprocessLang, StylePreprocessor> = {
styl,
stylus: styl
}
function getAbsolutePaths(relativePaths: string[], dirname: string): string[] {
return relativePaths.map(relativePath => path.join(dirname, relativePath))
}