Skip to content

Commit

Permalink
refactor: only rewrite css varaiable in <style scoped> when vars is…
Browse files Browse the repository at this point in the history
… present
  • Loading branch information
yyx990803 committed Jul 10, 2020
1 parent f3cc41f commit 73bfce3
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 44 deletions.
23 changes: 18 additions & 5 deletions packages/compiler-sfc/__tests__/compileStyle.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { compileStyle, compileStyleAsync } from '../src/compileStyle'
import {
compileStyle,
compileStyleAsync,
SFCStyleCompileOptions
} from '../src/compileStyle'
import { mockWarn } from '@vue/shared'

describe('SFC scoped CSS', () => {
mockWarn()

function compileScoped(source: string): string {
function compileScoped(
source: string,
options?: Partial<SFCStyleCompileOptions>
): string {
const res = compileStyle({
source,
filename: 'test.css',
id: 'test',
scoped: true
scoped: true,
...options
})
if (res.errors.length) {
res.errors.forEach(err => {
Expand Down Expand Up @@ -254,10 +262,15 @@ describe('SFC scoped CSS', () => {

describe('<style vars>', () => {
test('should rewrite CSS vars in scoped mode', () => {
const code = compileScoped(`.foo {
const code = compileScoped(
`.foo {
color: var(--color);
font-size: var(--global:font);
}`)
}`,
{
vars: true
}
)
expect(code).toMatchInlineSnapshot(`
".foo[test] {
color: var(--test-color);
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-sfc/src/compileScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export function compileScript(
}

// 2. check <script setup="xxx"> function signature
const setupValue = scriptSetup.attrs.setup
const setupValue = scriptSetup.setup
const hasExplicitSignature = typeof setupValue === 'string'

let propsVar: string | undefined
Expand Down
4 changes: 3 additions & 1 deletion packages/compiler-sfc/src/compileStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface SFCStyleCompileOptions {
id: string
map?: RawSourceMap
scoped?: boolean
vars?: boolean
trim?: boolean
preprocessLang?: PreprocessLang
preprocessOptions?: any
Expand Down Expand Up @@ -73,6 +74,7 @@ export function doCompileStyle(
filename,
id,
scoped = false,
vars = false,
trim = true,
modules = false,
modulesOptions = {},
Expand All @@ -90,7 +92,7 @@ export function doCompileStyle(
plugins.push(trimPlugin())
}
if (scoped) {
plugins.push(scopedPlugin(id))
plugins.push(scopedPlugin({ id, vars }))
}
let cssModules: Record<string, string> | undefined
if (modules) {
Expand Down
6 changes: 6 additions & 0 deletions packages/compiler-sfc/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@ export interface SFCTemplateBlock extends SFCBlock {

export interface SFCScriptBlock extends SFCBlock {
type: 'script'
setup?: string | boolean
bindings?: BindingMetadata
}

export interface SFCStyleBlock extends SFCBlock {
type: 'style'
scoped?: boolean
vars?: string
module?: string | boolean
}

Expand Down Expand Up @@ -266,11 +268,15 @@ function createBlock(
} else if (type === 'style') {
if (p.name === 'scoped') {
;(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') {
;(block as SFCStyleBlock).module = attrs[p.name]
}
} else if (type === 'template' && p.name === 'functional') {
;(block as SFCTemplateBlock).functional = true
} else if (type === 'script' && p.name === 'setup') {
;(block as SFCScriptBlock).setup = attrs.setup
}
}
})
Expand Down
75 changes: 38 additions & 37 deletions packages/compiler-sfc/src/stylePluginScoped.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const animationRE = /^(-\w+-)?animation$/
const cssVarRE = /\bvar\(--(global:)?([^)]+)\)/g

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)

root.each(function rewriteSelectors(node) {
Expand Down Expand Up @@ -135,44 +135,45 @@ export default postcss.plugin('vue-scoped', (options: any) => (root: Root) => {
})

const hasKeyframes = Object.keys(keyframes).length
root.walkDecls(decl => {
// If keyframes are found in this <style>, find and rewrite animation names
// in declarations.
// Caveat: this only works for keyframes and animation rules in the same
// <style> element.
if (hasKeyframes) {
// individual animation-name declaration
if (animationNameRE.test(decl.prop)) {
decl.value = decl.value
.split(',')
.map(v => keyframes[v.trim()] || v.trim())
.join(',')
}
// shorthand
if (animationRE.test(decl.prop)) {
decl.value = decl.value
.split(',')
.map(v => {
const vals = v.trim().split(/\s+/)
const i = vals.findIndex(val => keyframes[val])
if (i !== -1) {
vals.splice(i, 1, keyframes[vals[i]])
return vals.join(' ')
} else {
return v
}
})
.join(',')
if (hasKeyframes || hasInjectedVars)
root.walkDecls(decl => {
// If keyframes are found in this <style>, find and rewrite animation names
// in declarations.
// Caveat: this only works for keyframes and animation rules in the same
// <style> element.
if (hasKeyframes) {
// individual animation-name declaration
if (animationNameRE.test(decl.prop)) {
decl.value = decl.value
.split(',')
.map(v => keyframes[v.trim()] || v.trim())
.join(',')
}
// shorthand
if (animationRE.test(decl.prop)) {
decl.value = decl.value
.split(',')
.map(v => {
const vals = v.trim().split(/\s+/)
const i = vals.findIndex(val => keyframes[val])
if (i !== -1) {
vals.splice(i, 1, keyframes[vals[i]])
return vals.join(' ')
} else {
return v
}
})
.join(',')
}
}
}

// rewrite CSS variables
if (cssVarRE.test(decl.value)) {
decl.value = decl.value.replace(cssVarRE, (_, $1, $2) => {
return $1 ? `var(--${$2})` : `var(--${id}-${$2})`
})
}
})
// rewrite CSS variables
if (hasInjectedVars && cssVarRE.test(decl.value)) {
decl.value = decl.value.replace(cssVarRE, (_, $1, $2) => {
return $1 ? `var(--${$2})` : `var(--${id}-${$2})`
})
}
})
})

function isSpaceCombinator(node: Node) {
Expand Down

0 comments on commit 73bfce3

Please sign in to comment.