From 75bd62f1c6d3de7f4c2eb4457c7d34313628f818 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 2 Dec 2020 18:39:25 -0500 Subject: [PATCH 1/3] feat(compiler-sfc): upgrade to postcss 8 --- packages/compiler-sfc/package.json | 6 +- packages/compiler-sfc/src/compileStyle.ts | 44 +-- packages/compiler-sfc/src/cssVars.ts | 17 +- .../compiler-sfc/src/stylePluginScoped.ts | 331 ++++++++++-------- packages/compiler-sfc/src/stylePluginTrim.ts | 24 +- yarn.lock | 129 ++++--- 6 files changed, 300 insertions(+), 251 deletions(-) diff --git a/packages/compiler-sfc/package.json b/packages/compiler-sfc/package.json index c052df5c4b4..e6246977a87 100644 --- a/packages/compiler-sfc/package.json +++ b/packages/compiler-sfc/package.json @@ -41,13 +41,15 @@ "@vue/compiler-ssr": "3.0.4", "@vue/shared": "3.0.4", "consolidate": "^0.16.0", + "cssesc": "^3.0.0", "estree-walker": "^2.0.1", + "generic-names": "^3.0.0", "hash-sum": "^2.0.0", "lru-cache": "^5.1.1", "magic-string": "^0.25.7", "merge-source-map": "^1.1.0", - "postcss": "^7.0.32", - "postcss-modules": "^3.2.2", + "postcss": "^8.1.9", + "postcss-modules": "^4.0.0", "postcss-selector-parser": "^6.0.4", "source-map": "^0.6.1" }, diff --git a/packages/compiler-sfc/src/compileStyle.ts b/packages/compiler-sfc/src/compileStyle.ts index f9b7cbe417d..e43be62f01a 100644 --- a/packages/compiler-sfc/src/compileStyle.ts +++ b/packages/compiler-sfc/src/compileStyle.ts @@ -1,10 +1,5 @@ -import postcss, { - ProcessOptions, - LazyResult, - Result, - ResultMap, - ResultMessage -} from 'postcss' +import postcss, { ProcessOptions, Result, SourceMap, Message } from 'postcss' +import LazyResult from 'postcss/lib/lazy-result' import trimPlugin from './stylePluginTrim' import scopedPlugin from './stylePluginScoped' import { @@ -35,28 +30,33 @@ export interface SFCStyleCompileOptions { map?: RawSourceMap } +/** + * Aligns with postcss-modules + * https://github.com/css-modules/postcss-modules + */ +export interface CSSModulesOptions { + scopeBehaviour?: 'global' | 'local' + generateScopedName?: + | string + | ((name: string, filename: string, css: string) => string) + hashPrefix?: string + localsConvention?: 'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly' + exportGlobals?: boolean + globalModulePaths?: string[] +} + export interface SFCAsyncStyleCompileOptions extends SFCStyleCompileOptions { isAsync?: boolean // css modules support, note this requires async so that we can get the // resulting json modules?: boolean - // maps to postcss-modules options - // https://github.com/css-modules/postcss-modules - modulesOptions?: { - scopeBehaviour?: 'global' | 'local' - globalModulePaths?: string[] - generateScopedName?: - | string - | ((name: string, filename: string, css: string) => string) - hashPrefix?: string - localsConvention?: 'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly' - } + modulesOptions?: CSSModulesOptions } export interface SFCStyleCompileResults { code: string map: RawSourceMap | undefined - rawResult: LazyResult | Result | undefined + rawResult: Result | LazyResult | undefined errors: Error[] modules?: Record dependencies: Set @@ -149,7 +149,7 @@ export function doCompileStyle( let result: LazyResult | undefined let code: string | undefined - let outMap: ResultMap | undefined + let outMap: SourceMap | undefined // stylus output include plain css. so need remove the repeat item const dependencies = new Set( preProcessedSource ? preProcessedSource.dependencies : [] @@ -162,7 +162,7 @@ export function doCompileStyle( errors.push(...preProcessedSource.errors) } - const recordPlainCssDependencies = (messages: ResultMessage[]) => { + const recordPlainCssDependencies = (messages: Message[]) => { messages.forEach(msg => { if (msg.type === 'dependency') { // postcss output path is absolute position path @@ -226,7 +226,7 @@ function preprocess( return preprocessor( options.source, - options.map, + options.inMap || options.map, { filename: options.filename, ...options.preprocessOptions diff --git a/packages/compiler-sfc/src/cssVars.ts b/packages/compiler-sfc/src/cssVars.ts index 7489d1b511d..4fb721f963d 100644 --- a/packages/compiler-sfc/src/cssVars.ts +++ b/packages/compiler-sfc/src/cssVars.ts @@ -8,7 +8,7 @@ import { BindingMetadata } from '@vue/compiler-dom' import { SFCDescriptor } from './parse' -import postcss, { Root } from 'postcss' +import { PluginCreator } from 'postcss' import hash from 'hash-sum' export const CSS_VARS_HELPER = `useCssVars` @@ -49,20 +49,21 @@ export interface CssVarsPluginOptions { isProd: boolean } -export const cssVarsPlugin = postcss.plugin( - 'vue-scoped', - opts => (root: Root) => { - const { id, isProd } = opts! - root.walkDecls(decl => { +export const cssVarsPlugin: PluginCreator = opts => { + const { id, isProd } = opts! + return { + postcssPlugin: 'vue-sfc-vars', + Declaration(decl) { // rewrite CSS variables if (cssVarRE.test(decl.value)) { decl.value = decl.value.replace(cssVarRE, (_, $1, $2, $3) => { return `var(--${genVarName(id, $1 || $2 || $3, isProd)})` }) } - }) + } } -) +} +cssVarsPlugin.postcss = true export function genCssVarsCode( vars: string[], diff --git a/packages/compiler-sfc/src/stylePluginScoped.ts b/packages/compiler-sfc/src/stylePluginScoped.ts index 44265d5ba31..87c8795cd79 100644 --- a/packages/compiler-sfc/src/stylePluginScoped.ts +++ b/packages/compiler-sfc/src/stylePluginScoped.ts @@ -1,181 +1,202 @@ -import postcss, { Root } from 'postcss' -import selectorParser, { Node, Selector } from 'postcss-selector-parser' +import { PluginCreator, Rule } from 'postcss' +import selectorParser from 'postcss-selector-parser' import { warn } from './warn' const animationNameRE = /^(-\w+-)?animation-name$/ const animationRE = /^(-\w+-)?animation$/ -export default postcss.plugin('vue-scoped', (id: any) => (root: Root) => { +const scopedPlugin: PluginCreator = (id = '') => { const keyframes = Object.create(null) const shortId = id.replace(/^data-v-/, '') - root.each(function rewriteSelectors(node) { - if (node.type !== 'rule') { - // handle media queries - if (node.type === 'atrule') { - if (node.name === 'media' || node.name === 'supports') { - node.each(rewriteSelectors) - } else if (/-?keyframes$/.test(node.name)) { - // register keyframes - keyframes[node.params] = node.params = node.params + '-' + shortId - } + return { + postcssPlugin: 'vue-sfc-scoped', + Rule(rule) { + processRule(id, rule) + }, + AtRule(node) { + if ( + /-?keyframes$/.test(node.name) && + !node.params.endsWith(`-${shortId}`) + ) { + // register keyframes + keyframes[node.params] = node.params = node.params + '-' + shortId } - return - } - - node.selector = selectorParser(selectors => { - function rewriteSelector(selector: Selector, slotted?: boolean) { - let node: Node | null = null - let shouldInject = true - // find the last child node to insert attribute selector - selector.each(n => { - // DEPRECATED ">>>" and "/deep/" combinator - if ( - n.type === 'combinator' && - (n.value === '>>>' || n.value === '/deep/') - ) { - n.value = ' ' - n.spaces.before = n.spaces.after = '' - warn( - `the >>> and /deep/ combinators have been deprecated. ` + - `Use :deep() instead.` - ) - return false + }, + OnceExit(root) { + if (Object.keys(keyframes).length) { + // If keyframes are found in this