wip: css var injection production mode

This commit is contained in:
Evan You
2020-11-17 15:58:46 -05:00
parent f92bc5a19a
commit 94736f7729
7 changed files with 96 additions and 19 deletions

View File

@@ -40,6 +40,10 @@ export interface SFCScriptCompileOptions {
* This must be consistent with the `id` passed to `compileStyle`.
*/
id: string
/**
* Production mode. Used to determine whether to generate hashed CSS variables
*/
isProd?: boolean
/**
* https://babeljs.io/docs/en/babel-parser#plugins
*/
@@ -128,7 +132,14 @@ export function compileScript(
return {
...script,
content: cssVars.length
? injectCssVarsCalls(sfc, cssVars, bindings, scopeId, plugins)
? injectCssVarsCalls(
sfc,
cssVars,
bindings,
scopeId,
!!options.isProd,
plugins
)
: script.content,
bindings,
scriptAst
@@ -511,13 +522,15 @@ export function compileScript(
node.body.type === 'ExpressionStatement'
) {
if (enableRefSugar) {
warnOnce(
`ref: sugar is still an experimental proposal and is not ` +
`guaranteed to be a part of <script setup>.\n` +
`Follow its status at https://github.com/vuejs/rfcs/pull/228.\n` +
`It's also recommended to pin your vue dependencies to exact versions ` +
`to avoid breakage.`
)
if (__DEV__ && !__TEST__) {
warnOnce(
`ref: sugar is still an experimental proposal and is not ` +
`guaranteed to be a part of <script setup>.\n` +
`Follow its status at https://github.com/vuejs/rfcs/pull/228.\n` +
`It's also recommended to pin your vue dependencies to exact versions ` +
`to avoid breakage.`
)
}
s.overwrite(
node.label.start! + startOffset,
node.body.start! + startOffset,
@@ -800,7 +813,12 @@ export function compileScript(
helperImports.add('unref')
s.prependRight(
startOffset,
`\n${genCssVarsCode(cssVars, bindingMetadata, scopeId)}\n`
`\n${genCssVarsCode(
cssVars,
bindingMetadata,
scopeId,
!!options.isProd
)}\n`
)
}

View File

@@ -23,6 +23,7 @@ export interface SFCStyleCompileOptions {
map?: RawSourceMap
scoped?: boolean
trim?: boolean
isProd?: boolean
preprocessLang?: PreprocessLang
preprocessOptions?: any
preprocessCustomRequire?: (id: string) => any
@@ -82,6 +83,7 @@ export function doCompileStyle(
id,
scoped = false,
trim = true,
isProd = false,
modules = false,
modulesOptions = {},
preprocessLang,
@@ -94,7 +96,7 @@ export function doCompileStyle(
const source = preProcessedSource ? preProcessedSource.code : options.source
const plugins = (postcssPlugins || []).slice()
plugins.unshift(cssVarsPlugin(id))
plugins.unshift(cssVarsPlugin({ id, isProd }))
if (trim) {
plugins.push(trimPlugin())
}

View File

@@ -11,12 +11,17 @@ import { SFCDescriptor } from './parse'
import { rewriteDefault } from './rewriteDefault'
import { ParserPlugin } from '@babel/parser'
import postcss, { Root } from 'postcss'
import hash from 'hash-sum'
export const CSS_VARS_HELPER = `useCssVars`
export const cssVarRE = /\bv-bind\(\s*(?:'([^']+)'|"([^"]+)"|([^'"][^)]*))\s*\)/g
export function convertCssVarCasing(raw: string): string {
return raw.replace(/([^\w-])/g, '_')
export function genVarName(id: string, raw: string, isProd: boolean): string {
if (isProd) {
return hash(id + raw)
} else {
return `${id}-${raw.replace(/([^\w-])/g, '_')}`
}
}
export function parseCssVars(sfc: SFCDescriptor): string[] {
@@ -31,15 +36,21 @@ export function parseCssVars(sfc: SFCDescriptor): string[] {
}
// for compileStyle
export const cssVarsPlugin = postcss.plugin(
export interface CssVarsPluginOptions {
id: string
isProd: boolean
}
export const cssVarsPlugin = postcss.plugin<CssVarsPluginOptions>(
'vue-scoped',
(id: any) => (root: Root) => {
opts => (root: Root) => {
const { id, isProd } = opts!
const shortId = id.replace(/^data-v-/, '')
root.walkDecls(decl => {
// rewrite CSS variables
if (cssVarRE.test(decl.value)) {
decl.value = decl.value.replace(cssVarRE, (_, $1, $2, $3) => {
return `var(--${shortId}-${convertCssVarCasing($1 || $2 || $3)})`
return `var(--${genVarName(shortId, $1 || $2 || $3, isProd)})`
})
}
})
@@ -49,10 +60,11 @@ export const cssVarsPlugin = postcss.plugin(
export function genCssVarsCode(
vars: string[],
bindings: BindingMetadata,
id: string
id: string,
isProd: boolean
) {
const varsExp = `{\n ${vars
.map(v => `"${id}-${convertCssVarCasing(v)}": (${v})`)
.map(v => `"${genVarName(id, v, isProd)}": (${v})`)
.join(',\n ')}\n}`
const exp = createSimpleExpression(varsExp, false)
const context = createTransformContext(createRoot([]), {
@@ -82,6 +94,7 @@ export function injectCssVarsCalls(
cssVars: string[],
bindings: BindingMetadata,
id: string,
isProd: boolean,
parserPlugins: ParserPlugin[]
): string {
const script = rewriteDefault(
@@ -96,7 +109,8 @@ export function injectCssVarsCalls(
`const __injectCSSVars__ = () => {\n${genCssVarsCode(
cssVars,
bindings,
id
id,
isProd
)}}\n` +
`const __setup__ = __default__.setup\n` +
`__default__.setup = __setup__\n` +