wip: css var injection production mode
This commit is contained in:
parent
f92bc5a19a
commit
94736f7729
@ -49,6 +49,7 @@
|
||||
"@rollup/plugin-json": "^4.0.0",
|
||||
"@rollup/plugin-node-resolve": "^9.0.0",
|
||||
"@rollup/plugin-replace": "^2.2.1",
|
||||
"@types/hash-sum": "^1.0.0",
|
||||
"@types/jest": "^26.0.0",
|
||||
"@types/node": "^14.10.1",
|
||||
"@types/puppeteer": "^2.0.0",
|
||||
|
@ -52,7 +52,7 @@ describe('CSS vars injection', () => {
|
||||
assertCode(content)
|
||||
})
|
||||
|
||||
test('should rewrite CSS vars in scoped mode', () => {
|
||||
test('should rewrite CSS vars in compileStyle', () => {
|
||||
const { code } = compileStyle({
|
||||
source: `.foo {
|
||||
color: v-bind(color);
|
||||
@ -69,6 +69,37 @@ describe('CSS vars injection', () => {
|
||||
`)
|
||||
})
|
||||
|
||||
test('prod mode', () => {
|
||||
const { content } = compileSFCScript(
|
||||
`<script>const a = 1</script>\n` +
|
||||
`<style>div{
|
||||
color: v-bind(color);
|
||||
font-size: v-bind('font.size');
|
||||
}</style>`,
|
||||
{ isProd: true }
|
||||
)
|
||||
expect(content).toMatch(`_useCssVars(_ctx => ({
|
||||
"4003f1a6": (_ctx.color),
|
||||
"41b6490a": (_ctx.font.size)
|
||||
}))}`)
|
||||
|
||||
const { code } = compileStyle({
|
||||
source: `.foo {
|
||||
color: v-bind(color);
|
||||
font-size: v-bind('font.size');
|
||||
}`,
|
||||
filename: 'test.css',
|
||||
id: mockId,
|
||||
isProd: true
|
||||
})
|
||||
expect(code).toMatchInlineSnapshot(`
|
||||
".foo {
|
||||
color: var(--4003f1a6);
|
||||
font-size: var(--41b6490a);
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
describe('codegen', () => {
|
||||
test('<script> w/ no default export', () => {
|
||||
assertCode(
|
||||
|
@ -43,6 +43,7 @@
|
||||
"@vue/shared": "3.0.2",
|
||||
"consolidate": "^0.16.0",
|
||||
"estree-walker": "^2.0.1",
|
||||
"hash-sum": "^2.0.0",
|
||||
"lru-cache": "^5.1.1",
|
||||
"magic-string": "^0.25.7",
|
||||
"merge-source-map": "^1.1.0",
|
||||
|
@ -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`
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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` +
|
||||
|
10
yarn.lock
10
yarn.lock
@ -845,6 +845,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/hash-sum@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/hash-sum/-/hash-sum-1.0.0.tgz#838f4e8627887d42b162d05f3d96ca636c2bc504"
|
||||
integrity sha512-FdLBT93h3kcZ586Aee66HPCVJ6qvxVjBlDWNmxSGSbCZe9hTsjRKdSsl4y1T+3zfujxo9auykQMnFsfyHWD7wg==
|
||||
|
||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
|
||||
@ -3398,6 +3403,11 @@ hash-base@^3.0.0:
|
||||
inherits "^2.0.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
hash-sum@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a"
|
||||
integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
|
||||
|
||||
hash.js@^1.0.0, hash.js@^1.0.3:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
|
||||
|
Loading…
Reference in New Issue
Block a user