Skip to content

Commit

Permalink
feat: support postcss sugarss (vitejs#6705)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalybaev committed Sep 30, 2022
1 parent 291174d commit 8ede2f1
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 14 deletions.
4 changes: 4 additions & 0 deletions packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
"less": "*",
"sass": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
Expand All @@ -139,6 +140,9 @@
"less": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
Expand Down
3 changes: 2 additions & 1 deletion packages/vite/src/node/optimizer/scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,8 @@ function esbuildScanPlugin(
// css & json & wasm
build.onResolve(
{
filter: /\.(css|less|sass|scss|styl|stylus|pcss|postcss|json|wasm)$/
filter:
/\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss|json|wasm)$/
},
externalUnlessEntry
)
Expand Down
58 changes: 46 additions & 12 deletions packages/vite/src/node/plugins/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export interface CSSModulesOptions {
| null
}

const cssLangs = `\\.(css|less|sass|scss|styl|stylus|pcss|postcss)($|\\?)`
const cssLangs = `\\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)($|\\?)`
const cssLangRE = new RegExp(cssLangs)
const cssModuleRE = new RegExp(`\\.module${cssLangs}`)
const directRequestRE = /(\?|&)direct\b/
Expand All @@ -127,7 +127,13 @@ const enum PreprocessLang {
const enum PureCssLang {
css = 'css'
}
type CssLang = keyof typeof PureCssLang | keyof typeof PreprocessLang
const enum PostCssDialectLang {
sss = 'sugarss'
}
type CssLang =
| keyof typeof PureCssLang
| keyof typeof PreprocessLang
| keyof typeof PostCssDialectLang

export const isCSSRequest = (request: string): boolean =>
cssLangRE.test(request)
Expand All @@ -150,10 +156,10 @@ export const removedPureCssFilesCache = new WeakMap<

export const cssEntryFilesCache = new WeakMap<ResolvedConfig, Set<string>>()

const postcssConfigCache = new WeakMap<
ResolvedConfig,
PostCSSConfigResult | null
>()
const postcssConfigCache: Record<
string,
WeakMap<ResolvedConfig, PostCSSConfigResult | null>
> = {}

function encodePublicUrlsInCSS(config: ResolvedConfig) {
return config.command === 'build'
Expand Down Expand Up @@ -752,8 +758,8 @@ async function compileCSS(
// crawl them in order to register watch dependencies.
const needInlineImport = code.includes('@import')
const hasUrl = cssUrlRE.test(code) || cssImageSetRE.test(code)
const postcssConfig = await resolvePostcssConfig(config)
const lang = id.match(cssLangRE)?.[1] as CssLang | undefined
const postcssConfig = await resolvePostcssConfig(config, getCssDialect(lang))

// 1. plain css that needs no processing
if (
Expand Down Expand Up @@ -827,6 +833,15 @@ async function compileCSS(

// 3. postcss
const postcssOptions = (postcssConfig && postcssConfig.options) || {}

// for sugarss change parser
if (lang === 'sss') {
postcssOptions.parser = loadPreprocessor(
PostCssDialectLang.sss,
config.root
)
}

const postcssPlugins =
postcssConfig && postcssConfig.plugins ? postcssConfig.plugins.slice() : []

Expand Down Expand Up @@ -1050,9 +1065,15 @@ interface PostCSSConfigResult {
}

async function resolvePostcssConfig(
config: ResolvedConfig
config: ResolvedConfig,
dialect = 'css'
): Promise<PostCSSConfigResult | null> {
let result = postcssConfigCache.get(config)
postcssConfigCache[dialect] ??= new WeakMap<
ResolvedConfig,
PostCSSConfigResult | null
>()

let result = postcssConfigCache[dialect].get(config)
if (result !== undefined) {
return result
}
Expand Down Expand Up @@ -1089,7 +1110,7 @@ async function resolvePostcssConfig(
}
}

postcssConfigCache.set(config, result)
postcssConfigCache[dialect].set(config, result)
return result
}

Expand Down Expand Up @@ -1385,7 +1406,9 @@ export interface StylePreprocessorResults {
deps: string[]
}

const loadedPreprocessors: Partial<Record<PreprocessLang, any>> = {}
const loadedPreprocessors: Partial<
Record<PreprocessLang | PostCssDialectLang, any>
> = {}

// TODO: use dynamic import
const _require = createRequire(import.meta.url)
Expand All @@ -1397,7 +1420,14 @@ function loadPreprocessor(
lang: PreprocessLang.stylus,
root: string
): typeof Stylus
function loadPreprocessor(lang: PreprocessLang, root: string): any {
function loadPreprocessor(
lang: PostCssDialectLang.sss,
root: string
): PostCSS.Parser
function loadPreprocessor(
lang: PreprocessLang | PostCssDialectLang,
root: string
): any {
if (lang in loadedPreprocessors) {
return loadedPreprocessors[lang]
}
Expand Down Expand Up @@ -1809,3 +1839,7 @@ const preProcessors = Object.freeze({
function isPreProcessor(lang: any): lang is PreprocessLang {
return lang && lang in preProcessors
}

function getCssDialect(lang: CssLang | undefined): string {
return lang === 'sss' ? 'sss' : 'css'
}
22 changes: 22 additions & 0 deletions playground/css/__tests__/css.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,28 @@ test.runIf(isBuild)('warning can be suppressed by esbuild.logOverride', () => {
})
})

test('sugarss', async () => {
const imported = await page.$('.sugarss')
const atImport = await page.$('.sugarss-at-import')
const atImportAlias = await page.$('.sugarss-at-import-alias')

expect(await getColor(imported)).toBe('blue')
expect(await getColor(atImport)).toBe('darkslateblue')
expect(await getBg(atImport)).toMatch(isBuild ? /base64/ : '/nested/icon.png')
expect(await getColor(atImportAlias)).toBe('darkslateblue')
expect(await getBg(atImportAlias)).toMatch(
isBuild ? /base64/ : '/nested/icon.png'
)

editFile('sugarss.sss', (code) => code.replace('color: blue', 'color: coral'))
await untilUpdated(() => getColor(imported), 'coral')

editFile('nested/nested.sss', (code) =>
code.replace('color: darkslateblue', 'color: blue')
)
await untilUpdated(() => getColor(atImport), 'blue')
})

// NOTE: the match inline snapshot should generate by build mode
test('async css order', async () => {
await withRetry(async () => {
Expand Down
11 changes: 11 additions & 0 deletions playground/css/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ <h1>CSS</h1>
<p>Imported Stylus string:</p>
<pre class="imported-stylus"></pre>

<p class="sugarss">SugarSS: This should be blue</p>
<p class="sugarss-at-import">
@import from SugarSS: This should be darkslateblue and have bg image
</p>
<p class="sugarss-at-import-alias">
@import from SugarSS: This should be darkslateblue and have bg image which
url contains alias
</p>
<p>Imported SugarSS string:</p>
<pre class="imported-sugarss"></pre>

<p class="modules">CSS modules: this should be turquoise</p>
<p>Imported CSS module:</p>
<pre class="modules-code"></pre>
Expand Down
3 changes: 3 additions & 0 deletions playground/css/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import './minify.css'
import css from './imported.css'
text('.imported-css', css)

import sugarss from './sugarss.sss'
text('.imported-sugarss', sugarss)

import sass from './sass.scss'
text('.imported-sass', sass)

Expand Down
8 changes: 8 additions & 0 deletions playground/css/nested/nested.sss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.sugarss-at-import
color: darkslateblue
background: url(./icon.png) 10px no-repeat


.sugarss-at-import-alias
color: darkslateblue
background: url(@/nested/icon.png) 10px no-repeat
3 changes: 2 additions & 1 deletion playground/css/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"less": "^4.1.3",
"postcss-nested": "^5.0.6",
"sass": "^1.55.0",
"stylus": "^0.59.0"
"stylus": "^0.59.0",
"sugarss": "^4.0.1"
}
}
4 changes: 4 additions & 0 deletions playground/css/sugarss.sss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@import '@/nested/nested.sss'

.sugarss
color: blue
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8ede2f1

Please sign in to comment.