Skip to content

Commit

Permalink
feat: generate preflights on demand
Browse files Browse the repository at this point in the history
  • Loading branch information
MellowCo committed Dec 7, 2024
1 parent 2074203 commit 1075e79
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 36 deletions.
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export interface PresetWeappOptions extends PresetOptions {
*
* @default true
*/
preflight?: boolean
preflight?: boolean | 'on-demand'

/**
* 是否转换微信class
Expand Down Expand Up @@ -198,7 +198,7 @@ export const presetWeapp = definePreset((options: PresetWeappOptions = {}) => {
if (options.platform === 'uniapp' && options.isH5)
uniAppVue2CssRpxTransform(css)
},
preflights: options.preflight ? preflights(options.isH5, options.platform) : [],
preflights: preflights(options),
prefix: options.prefix,
extractorDefault: options.arbitraryVariants === false
? undefined
Expand Down
54 changes: 35 additions & 19 deletions src/preflights.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Preflight, PreflightContext } from '@unocss/core'
import type { PresetWeappOptions } from '.'
import type { Theme } from './theme'
import { entriesToCss, toArray } from '@unocss/core'

Expand All @@ -7,26 +8,41 @@ const taroPrefix = ['*,::before,::after']
const uniappPrefix = ['uni-page-body,::before,::after']
// const defaultPrefix = ['*,::before,::after', '::backdrop']

export default function (isH5: boolean, platform: string): Preflight[] {
return [
{
layer: 'preflights',
getCSS(ctx: PreflightContext<Theme>) {
if (ctx.theme.preflightBase) {
const css = entriesToCss(Object.entries(ctx.theme.preflightBase))
let preflightRoot = ctx.theme.preflightRoot
export default function (options: PresetWeappOptions): Preflight<Theme>[] | undefined {
if (options.preflight) {
return [
{
layer: 'preflights',
getCSS({ theme, generator }) {
if (theme.preflightBase) {
// let entries = entriesToCss(Object.entries(theme.preflightBase))
let entries = Object.entries(theme.preflightBase)
if (options.preflight === 'on-demand') {
const keys = new Set(Array.from(generator.activatedRules).map(r => r[2]?.custom?.preflightKeys).filter(Boolean).flat())
entries = entries.filter(([k]) => keys.has(k))
}

if (!preflightRoot) {
if (isH5)
preflightRoot = platform === 'uniapp' ? uniappPrefix : taroPrefix
else
preflightRoot = wxPrefix
}
if (entries.length > 0) {
let css = entriesToCss(entries)
if (options.variablePrefix !== 'un-') {
css = css.replace(/--un-/g, `--${options.variablePrefix}`)
}

let preflightRoot = theme.preflightRoot

const roots = toArray(preflightRoot)
return roots.map(root => `${root}{${css}}`).join('')
}
if (!preflightRoot) {
if (options.isH5)
preflightRoot = options.platform === 'uniapp' ? uniappPrefix : taroPrefix
else
preflightRoot = wxPrefix
}

const roots = toArray(preflightRoot)
return roots.map(root => `${root}{${css}}`).join('')
}
}
},
},
},
]
]
}
}
4 changes: 3 additions & 1 deletion src/rules/ring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export const ringBase = {
'--un-shadow': '0 0 rgb(0 0 0 / 0)',
}

const preflightKeys = Object.keys(ringBase)

export const rings: Rule<Theme>[] = [
// size
[/^ring(?:-(.+))?$/, ([, d], { theme }) => {
Expand All @@ -24,7 +26,7 @@ export const rings: Rule<Theme>[] = [
'box-shadow': 'var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow)',
}
}
}, { autocomplete: 'ring-$ringWidth' }],
}, { custom: { preflightKeys }, autocomplete: 'ring-$ringWidth' }],

// size
[/^ring-(?:width-|size-)(.+)$/, handleWidth, { autocomplete: 'ring-(width|size)-$lineWidth' }],
Expand Down
4 changes: 3 additions & 1 deletion src/rules/shadow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export const boxShadowsBase = {
'--un-shadow': '0 0 rgb(0 0 0 / 0)',
}

const preflightKeys = Object.keys(boxShadowsBase)

export const boxShadows: Rule<Theme>[] = [
[/^shadow(?:-(.+))?$/, (match, context) => {
let [, d] = match
Expand All @@ -27,7 +29,7 @@ export const boxShadows: Rule<Theme>[] = [
}
}
return colorResolver('--un-shadow-color', 'shadow', 'shadowColor')(match, context)
}, { autocomplete: ['shadow-$colors', 'shadow-$boxShadow'] }],
}, { custom: { preflightKeys }, autocomplete: ['shadow-$colors', 'shadow-$boxShadow'] }],
[/^shadow-op(?:acity)?-?(.+)$/, ([, opacity]) => ({ '--un-shadow-opacity': h.bracket.percent.cssvar(opacity) }), { autocomplete: 'shadow-(op|opacity)-<percent>' }],

// inset
Expand Down
32 changes: 20 additions & 12 deletions src/rules/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,15 @@ export const transformBase = {
'--un-translate-z': 0,
}

const preflightKeys = Object.keys(transformBase)

export const transforms: Rule[] = [
// origins
[/^(?:transform-)?origin-(.+)$/, ([, s]) => ({ 'transform-origin': positionMap[s] ?? h.bracket.cssvar(s) }), { autocomplete: [`transform-origin-(${Object.keys(positionMap).join('|')})`, `origin-(${Object.keys(positionMap).join('|')})`] }],
[
/^(?:transform-)?origin-(.+)$/,
([, s]) => ({ 'transform-origin': positionMap[s] ?? h.bracket.cssvar(s) }),
{ autocomplete: [`transform-origin-(${Object.keys(positionMap).join('|')})`, `origin-(${Object.keys(positionMap).join('|')})`] },
],

// perspectives
[/^(?:transform-)?perspect(?:ive)?-(.+)$/, ([, s]) => {
Expand All @@ -95,23 +101,25 @@ export const transforms: Rule[] = [
}],

// modifiers
[/^(?:transform-)?translate-()(.+)$/, handleTranslate],
[/^(?:transform-)?translate-([xyz])-(.+)$/, handleTranslate],
[/^(?:transform-)?rotate-()(.+)$/, handleRotate],
[/^(?:transform-)?rotate-([xyz])-(.+)$/, handleRotate],
[/^(?:transform-)?skew-()(.+)$/, handleSkew],
[/^(?:transform-)?skew-([xy])-(.+)$/, handleSkew, { autocomplete: ['transform-skew-(x|y)-<percent>', 'skew-(x|y)-<percent>'] }],
[/^(?:transform-)?scale-()(.+)$/, handleScale],
[/^(?:transform-)?scale-([xyz])-(.+)$/, handleScale, { autocomplete: [`transform-(${transformValues.join('|')})-<percent>`, `transform-(${transformValues.join('|')})-(x|y|z)-<percent>`, `(${transformValues.join('|')})-<percent>`, `(${transformValues.join('|')})-(x|y|z)-<percent>`] }],
[/^(?:transform-)?translate-()(.+)$/, handleTranslate, { custom: { preflightKeys } }],
[/^(?:transform-)?translate-([xyz])-(.+)$/, handleTranslate, { custom: { preflightKeys } }],
[/^(?:transform-)?rotate-()(.+)$/, handleRotate, { custom: { preflightKeys } }],
[/^(?:transform-)?rotate-([xyz])-(.+)$/, handleRotate, { custom: { preflightKeys } }],
[/^(?:transform-)?skew-()(.+)$/, handleSkew, { custom: { preflightKeys } }],
[/^(?:transform-)?skew-([xy])-(.+)$/, handleSkew, { custom: { preflightKeys }, autocomplete: ['transform-skew-(x|y)-<percent>', 'skew-(x|y)-<percent>'] }],
[/^(?:transform-)?scale-()(.+)$/, handleScale, { custom: { preflightKeys } }],
[/^(?:transform-)?scale-([xyz])-(.+)$/, handleScale, { custom: { preflightKeys }, autocomplete: [`transform-(${transformValues.join('|')})-<percent>`, `transform-(${transformValues.join('|')})-(x|y|z)-<percent>`, `(${transformValues.join('|')})-<percent>`, `(${transformValues.join('|')})-(x|y|z)-<percent>`] }],

// style
[/^(?:transform-)?preserve-3d$/, () => ({ 'transform-style': 'preserve-3d' })],
[/^(?:transform-)?preserve-flat$/, () => ({ 'transform-style': 'flat' })],

// base
['transform', { transform }],
['transform-cpu', { transform: transformCpu }],
['transform-gpu', { transform: transformGpu }],
['transform', { transform }, { custom: { preflightKeys } }],
['transform-cpu', { transform: transformCpu }, {
custom: { preflightKeys: ['--un-translate-x', '--un-translate-y', '--un-rotate', '--un-rotate-z', '--un-skew-x', '--un-skew-y', '--un-scale-x', '--un-scale-y'] },
}],
['transform-gpu', { transform: transformGpu }, { custom: { preflightKeys } }],
['transform-none', { transform: 'none' }],
...makeGlobalStaticRules('transform'),
]
Expand Down
2 changes: 1 addition & 1 deletion test/assets/output/preset-mini/targets.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* layer: preflights */
page,root-portal-content,::before,::after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset:var(--un-empty,/*!*/ /*!*/);--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset:var(--un-empty,/*!*/ /*!*/);--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / 0.5);--un-blur:var(--un-empty,/*!*/ /*!*/);--un-brightness:var(--un-empty,/*!*/ /*!*/);--un-contrast:var(--un-empty,/*!*/ /*!*/);--un-drop-shadow:var(--un-empty,/*!*/ /*!*/);--un-grayscale:var(--un-empty,/*!*/ /*!*/);--un-hue-rotate:var(--un-empty,/*!*/ /*!*/);--un-invert:var(--un-empty,/*!*/ /*!*/);--un-saturate:var(--un-empty,/*!*/ /*!*/);--un-sepia:var(--un-empty,/*!*/ /*!*/);--un-backdrop-blur:var(--un-empty,/*!*/ /*!*/);--un-backdrop-brightness:var(--un-empty,/*!*/ /*!*/);--un-backdrop-contrast:var(--un-empty,/*!*/ /*!*/);--un-backdrop-grayscale:var(--un-empty,/*!*/ /*!*/);--un-backdrop-hue-rotate:var(--un-empty,/*!*/ /*!*/);--un-backdrop-invert:var(--un-empty,/*!*/ /*!*/);--un-backdrop-opacity:var(--un-empty,/*!*/ /*!*/);--un-backdrop-saturate:var(--un-empty,/*!*/ /*!*/);--un-backdrop-sepia:var(--un-empty,/*!*/ /*!*/);}
page,root-portal-content,::before,::after{--licl-rotate:0;--licl-rotate-x:0;--licl-rotate-y:0;--licl-rotate-z:0;--licl-scale-x:1;--licl-scale-y:1;--licl-scale-z:1;--licl-skew-x:0;--licl-skew-y:0;--licl-translate-x:0;--licl-translate-y:0;--licl-translate-z:0;--licl-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--licl-ring-shadow:0 0 rgb(0 0 0 / 0);--licl-shadow-inset:var(--licl-empty,/*!*/ /*!*/);--licl-shadow:0 0 rgb(0 0 0 / 0);--licl-ring-inset:var(--licl-empty,/*!*/ /*!*/);--licl-ring-offset-width:0px;--licl-ring-offset-color:#fff;--licl-ring-width:0px;--licl-ring-color:rgb(147 197 253 / 0.5);--licl-blur:var(--licl-empty,/*!*/ /*!*/);--licl-brightness:var(--licl-empty,/*!*/ /*!*/);--licl-contrast:var(--licl-empty,/*!*/ /*!*/);--licl-drop-shadow:var(--licl-empty,/*!*/ /*!*/);--licl-grayscale:var(--licl-empty,/*!*/ /*!*/);--licl-hue-rotate:var(--licl-empty,/*!*/ /*!*/);--licl-invert:var(--licl-empty,/*!*/ /*!*/);--licl-saturate:var(--licl-empty,/*!*/ /*!*/);--licl-sepia:var(--licl-empty,/*!*/ /*!*/);--licl-backdrop-blur:var(--licl-empty,/*!*/ /*!*/);--licl-backdrop-brightness:var(--licl-empty,/*!*/ /*!*/);--licl-backdrop-contrast:var(--licl-empty,/*!*/ /*!*/);--licl-backdrop-grayscale:var(--licl-empty,/*!*/ /*!*/);--licl-backdrop-hue-rotate:var(--licl-empty,/*!*/ /*!*/);--licl-backdrop-invert:var(--licl-empty,/*!*/ /*!*/);--licl-backdrop-opacity:var(--licl-empty,/*!*/ /*!*/);--licl-backdrop-saturate:var(--licl-empty,/*!*/ /*!*/);--licl-backdrop-sepia:var(--licl-empty,/*!*/ /*!*/);}
/* layer: 1 */
.uno-layer-1\:translate-0{--licl-translate-x:0;--licl-translate-y:0;transform:translateX(var(--licl-translate-x)) translateY(var(--licl-translate-y)) translateZ(var(--licl-translate-z)) rotate(var(--licl-rotate)) rotateX(var(--licl-rotate-x)) rotateY(var(--licl-rotate-y)) rotateZ(var(--licl-rotate-z)) skewX(var(--licl-skew-x)) skewY(var(--licl-skew-y)) scaleX(var(--licl-scale-x)) scaleY(var(--licl-scale-y)) scaleZ(var(--licl-scale-z));}
/* layer: default */
Expand Down
47 changes: 47 additions & 0 deletions test/preflights.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,53 @@ import { createGenerator } from '@unocss/core'
import { describe, expect, it } from 'vitest'
import presetWeapp from '../src'

describe('on demand generate preflights', () => {
it('default preflights', async () => {
const uno = await createGenerator({
presets: [
presetWeapp({ preflight: 'on-demand' }),
],
})
const { css: noPreflightCSS } = await uno.generate('text-red')
expect(noPreflightCSS).toMatchInlineSnapshot(`
"/* layer: default */
.text-red{--un-text-opacity:1;color:rgb(248 113 113 / var(--un-text-opacity));}"
`)

const { css: hasPreflightCSS } = await uno.generate('ring')
expect(hasPreflightCSS).toMatchInlineSnapshot(`
"/* layer: preflights */
page,root-portal-content,::before,::after{--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset:var(--un-empty,/*!*/ /*!*/);--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / 0.5);}
/* layer: default */
.ring{--un-ring-width:3px;--un-ring-offset-shadow:var(--un-ring-inset) 0 0 0 var(--un-ring-offset-width) var(--un-ring-offset-color);--un-ring-shadow:var(--un-ring-inset) 0 0 0 calc(var(--un-ring-width) + var(--un-ring-offset-width)) var(--un-ring-color);box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}"
`)
})

it('custom depends', async () => {
const uno = await createGenerator({
presets: [
presetWeapp({ preflight: 'on-demand' }),
],
rules: [
[
'custom-rule',
{ blur: 'var(--un-shadow)' },
// depend on `--shadow` from presetMini
{ custom: { preflightKeys: '--un-shadow' } },
],
],
})
const { css } = await uno.generate('custom-rule')

expect(css).toMatchInlineSnapshot(`
"/* layer: preflights */
page,root-portal-content,::before,::after{--un-shadow:0 0 rgb(0 0 0 / 0);}
/* layer: default */
.custom-rule{blur:var(--un-shadow);}"
`)
})
})

describe('preflights', () => {
it('original preflight', async () => {
const uno = await createGenerator({
Expand Down

0 comments on commit 1075e79

Please sign in to comment.