refactor: only rewrite css varaiable in <style scoped> when vars is present

This commit is contained in:
Evan You 2020-07-10 17:10:48 -04:00
parent f3cc41f0c8
commit 73bfce3706
5 changed files with 66 additions and 44 deletions

View File

@ -1,15 +1,23 @@
import { compileStyle, compileStyleAsync } from '../src/compileStyle' import {
compileStyle,
compileStyleAsync,
SFCStyleCompileOptions
} from '../src/compileStyle'
import { mockWarn } from '@vue/shared' import { mockWarn } from '@vue/shared'
describe('SFC scoped CSS', () => { describe('SFC scoped CSS', () => {
mockWarn() mockWarn()
function compileScoped(source: string): string { function compileScoped(
source: string,
options?: Partial<SFCStyleCompileOptions>
): string {
const res = compileStyle({ const res = compileStyle({
source, source,
filename: 'test.css', filename: 'test.css',
id: 'test', id: 'test',
scoped: true scoped: true,
...options
}) })
if (res.errors.length) { if (res.errors.length) {
res.errors.forEach(err => { res.errors.forEach(err => {
@ -254,10 +262,15 @@ describe('SFC scoped CSS', () => {
describe('<style vars>', () => { describe('<style vars>', () => {
test('should rewrite CSS vars in scoped mode', () => { test('should rewrite CSS vars in scoped mode', () => {
const code = compileScoped(`.foo { const code = compileScoped(
`.foo {
color: var(--color); color: var(--color);
font-size: var(--global:font); font-size: var(--global:font);
}`) }`,
{
vars: true
}
)
expect(code).toMatchInlineSnapshot(` expect(code).toMatchInlineSnapshot(`
".foo[test] { ".foo[test] {
color: var(--test-color); color: var(--test-color);

View File

@ -174,7 +174,7 @@ export function compileScript(
} }
// 2. check <script setup="xxx"> function signature // 2. check <script setup="xxx"> function signature
const setupValue = scriptSetup.attrs.setup const setupValue = scriptSetup.setup
const hasExplicitSignature = typeof setupValue === 'string' const hasExplicitSignature = typeof setupValue === 'string'
let propsVar: string | undefined let propsVar: string | undefined

View File

@ -15,6 +15,7 @@ export interface SFCStyleCompileOptions {
id: string id: string
map?: RawSourceMap map?: RawSourceMap
scoped?: boolean scoped?: boolean
vars?: boolean
trim?: boolean trim?: boolean
preprocessLang?: PreprocessLang preprocessLang?: PreprocessLang
preprocessOptions?: any preprocessOptions?: any
@ -73,6 +74,7 @@ export function doCompileStyle(
filename, filename,
id, id,
scoped = false, scoped = false,
vars = false,
trim = true, trim = true,
modules = false, modules = false,
modulesOptions = {}, modulesOptions = {},
@ -90,7 +92,7 @@ export function doCompileStyle(
plugins.push(trimPlugin()) plugins.push(trimPlugin())
} }
if (scoped) { if (scoped) {
plugins.push(scopedPlugin(id)) plugins.push(scopedPlugin({ id, vars }))
} }
let cssModules: Record<string, string> | undefined let cssModules: Record<string, string> | undefined
if (modules) { if (modules) {

View File

@ -40,12 +40,14 @@ export interface SFCTemplateBlock extends SFCBlock {
export interface SFCScriptBlock extends SFCBlock { export interface SFCScriptBlock extends SFCBlock {
type: 'script' type: 'script'
setup?: string | boolean
bindings?: BindingMetadata bindings?: BindingMetadata
} }
export interface SFCStyleBlock extends SFCBlock { export interface SFCStyleBlock extends SFCBlock {
type: 'style' type: 'style'
scoped?: boolean scoped?: boolean
vars?: string
module?: string | boolean module?: string | boolean
} }
@ -266,11 +268,15 @@ function createBlock(
} else if (type === 'style') { } else if (type === 'style') {
if (p.name === 'scoped') { if (p.name === 'scoped') {
;(block as SFCStyleBlock).scoped = true ;(block as SFCStyleBlock).scoped = true
} else if (p.name === 'vars' && typeof attrs.vars === 'string') {
;(block as SFCStyleBlock).vars = attrs.vars
} else if (p.name === 'module') { } else if (p.name === 'module') {
;(block as SFCStyleBlock).module = attrs[p.name] ;(block as SFCStyleBlock).module = attrs[p.name]
} }
} else if (type === 'template' && p.name === 'functional') { } else if (type === 'template' && p.name === 'functional') {
;(block as SFCTemplateBlock).functional = true ;(block as SFCTemplateBlock).functional = true
} else if (type === 'script' && p.name === 'setup') {
;(block as SFCScriptBlock).setup = attrs.setup
} }
} }
}) })

View File

@ -6,7 +6,7 @@ const animationRE = /^(-\w+-)?animation$/
const cssVarRE = /\bvar\(--(global:)?([^)]+)\)/g const cssVarRE = /\bvar\(--(global:)?([^)]+)\)/g
export default postcss.plugin('vue-scoped', (options: any) => (root: Root) => { export default postcss.plugin('vue-scoped', (options: any) => (root: Root) => {
const id: string = options const { id, vars: hasInjectedVars } = options as { id: string; vars: boolean }
const keyframes = Object.create(null) const keyframes = Object.create(null)
root.each(function rewriteSelectors(node) { root.each(function rewriteSelectors(node) {
@ -135,6 +135,7 @@ export default postcss.plugin('vue-scoped', (options: any) => (root: Root) => {
}) })
const hasKeyframes = Object.keys(keyframes).length const hasKeyframes = Object.keys(keyframes).length
if (hasKeyframes || hasInjectedVars)
root.walkDecls(decl => { root.walkDecls(decl => {
// If keyframes are found in this <style>, find and rewrite animation names // If keyframes are found in this <style>, find and rewrite animation names
// in declarations. // in declarations.
@ -167,7 +168,7 @@ export default postcss.plugin('vue-scoped', (options: any) => (root: Root) => {
} }
// rewrite CSS variables // rewrite CSS variables
if (cssVarRE.test(decl.value)) { if (hasInjectedVars && cssVarRE.test(decl.value)) {
decl.value = decl.value.replace(cssVarRE, (_, $1, $2) => { decl.value = decl.value.replace(cssVarRE, (_, $1, $2) => {
return $1 ? `var(--${$2})` : `var(--${id}-${$2})` return $1 ? `var(--${$2})` : `var(--${id}-${$2})`
}) })