Skip to content

Commit

Permalink
feat: createCSSCompiler support add hmr deps
Browse files Browse the repository at this point in the history
  • Loading branch information
poyoho committed Apr 28, 2022
1 parent 0ef0a62 commit 43c3dce
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 113 deletions.
185 changes: 88 additions & 97 deletions packages/vite/src/node/plugins/css.ts
Expand Up @@ -94,6 +94,20 @@ export interface CSSModulesOptions {
| null
}

interface CompileCSSResult {
code: string
map?: SourceMapInput
ast?: PostCSS.Result
modules?: Record<string, string>
deps?: Set<string>
}

type CSSCompiler = (
id: string,
raw: string,
ssr?: boolean
) => Promise<CompileCSSResult>

const cssLangs = `\\.(css|less|sass|scss|styl|stylus|pcss|postcss)($|\\?)`
const cssLangRE = new RegExp(cssLangs)
const cssModuleRE = new RegExp(`\\.module${cssLangs}`)
Expand Down Expand Up @@ -146,13 +160,7 @@ const postcssConfigCache = new WeakMap<
export function cssPlugin(config: ResolvedConfig): Plugin {
let server: ViteDevServer
let moduleCache: Map<string, Record<string, string>>

const resolveUrl = config.createResolver({
preferRelative: true,
tryIndex: false,
extensions: []
})
const atImportResolvers = createCSSResolvers(config)
let cssCompiler: CSSCompiler

return {
name: 'vite:css',
Expand All @@ -177,87 +185,9 @@ export function cssPlugin(config: ResolvedConfig): Plugin {
) {
return
}
cssCompiler ||= createCSSCompiler(config, this, server)
const ssr = options?.ssr === true

const urlReplacer: CssUrlReplacer = async (url, importer) => {
if (checkPublicFile(url, config)) {
return config.base + url.slice(1)
}
const resolved = await resolveUrl(url, importer)
if (resolved) {
return fileToUrl(resolved, config, this)
}
return url
}

const {
code: css,
modules,
deps,
map
} = await compileCSS(
id,
raw,
config,
urlReplacer,
atImportResolvers,
server
)
if (modules) {
moduleCache.set(id, modules)
}

// track deps for build watch mode
if (config.command === 'build' && config.build.watch && deps) {
for (const file of deps) {
this.addWatchFile(file)
}
}

// dev
if (server) {
// server only logic for handling CSS @import dependency hmr
const { moduleGraph } = server
const thisModule = moduleGraph.getModuleById(id)
if (thisModule) {
// CSS modules cannot self-accept since it exports values
const isSelfAccepting = !modules && !inlineRE.test(id)
if (deps) {
// record deps in the module graph so edits to @import css can trigger
// main import to hot update
const depModules = new Set<string | ModuleNode>()
for (const file of deps) {
depModules.add(
isCSSRequest(file)
? moduleGraph.createFileOnlyEntry(file)
: await moduleGraph.ensureEntryFromUrl(
(
await fileToUrl(file, config, this)
).replace(
(config.server?.origin ?? '') + config.base,
'/'
),
ssr
)
)
}
moduleGraph.updateModuleInfo(
thisModule,
depModules,
// The root CSS proxy module is self-accepting and should not
// have an explicit accept list
new Set(),
isSelfAccepting,
ssr
)
for (const file of deps) {
this.addWatchFile(file)
}
} else {
thisModule.isSelfAccepting = isSelfAccepting
}
}
}
const { code: css, map } = await cssCompiler(id, raw, ssr)

return {
code: css,
Expand Down Expand Up @@ -615,7 +545,11 @@ function getCssResolversKeys(
return Object.keys(resolvers) as unknown as Array<keyof CSSAtImportResolvers>
}

export function createCSSCompiler(config: ResolvedConfig, ctx: PluginContext) {
export function createCSSCompiler(
config: ResolvedConfig,
ctx: PluginContext,
server?: ViteDevServer
): CSSCompiler {
const resolveUrl = config.createResolver({
preferRelative: true,
tryIndex: false,
Expand All @@ -634,8 +568,71 @@ export function createCSSCompiler(config: ResolvedConfig, ctx: PluginContext) {
return url
}

return (id: string, code: string) =>
compileCSS(id, code, config, urlReplacer, atImportResolvers)
return async (id: string, raw: string, ssr?: boolean) => {
const compiledResult = await compileCSS(
id,
raw,
config,
urlReplacer,
atImportResolvers,
server
)
const { modules, deps } = compiledResult
if (modules) {
cssModulesCache.get(config)?.set(id, modules)
}

// track deps for build watch mode
if (config.command === 'build' && config.build.watch && deps) {
for (const file of deps) {
ctx.addWatchFile(file)
}
}

// dev
if (server) {
// server only logic for handling CSS @import dependency hmr
const { moduleGraph } = server
const thisModule = moduleGraph.getModuleById(id)
if (thisModule) {
// CSS modules cannot self-accept since it exports values
const isSelfAccepting = !modules && !inlineRE.test(id)
if (deps) {
// record deps in the module graph so edits to @import css can trigger
// main import to hot update
const depModules = new Set<string | ModuleNode>()
for (const file of deps) {
depModules.add(
isCSSRequest(file)
? moduleGraph.createFileOnlyEntry(file)
: await moduleGraph.ensureEntryFromUrl(
(
await fileToUrl(file, config, ctx)
).replace((config.server?.origin ?? '') + config.base, '/'),
ssr
)
)
}
moduleGraph.updateModuleInfo(
thisModule,
depModules,
// The root CSS proxy module is self-accepting and should not
// have an explicit accept list
new Set(),
isSelfAccepting,
ssr
)
for (const file of deps) {
ctx.addWatchFile(file)
}
} else {
thisModule.isSelfAccepting = isSelfAccepting
}
}
}

return compiledResult
}
}

async function compileCSS(
Expand All @@ -645,13 +642,7 @@ async function compileCSS(
urlReplacer: CssUrlReplacer,
atImportResolvers: CSSAtImportResolvers,
server?: ViteDevServer
): Promise<{
code: string
map?: SourceMapInput
ast?: PostCSS.Result
modules?: Record<string, string>
deps?: Set<string>
}> {
): Promise<CompileCSSResult> {
const {
modules: modulesOptions,
preprocessorOptions,
Expand Down
26 changes: 10 additions & 16 deletions packages/vite/src/node/server/middlewares/indexHtml.ts
Expand Up @@ -101,7 +101,7 @@ const devHtmlHook: IndexHtmlTransformHook = async (
{ path: htmlPath, filename, server, originalUrl }
) => {
// css compile need to emitFile in build mode, and serve mode is not need.
const compileCSS = createCSSCompiler(server!.config, null as any)
const compileCSS = createCSSCompiler(server!.config, null as any, server)
const { config, moduleGraph } = server!
const base = config.base || '/'

Expand All @@ -110,7 +110,7 @@ const devHtmlHook: IndexHtmlTransformHook = async (
const filePath = cleanUrl(htmlPath)
const styleUrl: AssetNode[] = []

const addInlineModule = (node: ElementNode, ext: 'js' | 'css') => {
const addInlineModule = (node: ElementNode, ext: 'js') => {
inlineModuleIndex++

const url = filePath.replace(normalizePath(config.root), '')
Expand All @@ -137,17 +137,12 @@ const devHtmlHook: IndexHtmlTransformHook = async (
if (module) {
server?.moduleGraph.invalidateModule(module)
}
if (ext === 'js') {
s.overwrite(
node.loc.start.offset,
node.loc.end.offset,
`<script type="module" src="${modulePath}"></script>`,
{ contentOnly: true }
)
} else if (ext === 'css') {
// just use the style update hmr don't render css
s.append(`<script type="module" src="${modulePath}"></script>`)
}
s.overwrite(
node.loc.start.offset,
node.loc.end.offset,
`<script type="module" src="${modulePath}"></script>`,
{ contentOnly: true }
)
}

await traverseHtml(html, htmlPath, (node) => {
Expand All @@ -173,7 +168,6 @@ const devHtmlHook: IndexHtmlTransformHook = async (
end: children.loc.end.offset,
code: children.content
})
addInlineModule(node, 'css')
}

// elements with [href/src] attrs
Expand All @@ -192,8 +186,8 @@ const devHtmlHook: IndexHtmlTransformHook = async (
})

for (const { start, end, code } of styleUrl) {
const compliedCode = await compileCSS(filename + '.css', code)
s.overwrite(start, end, compliedCode.code)
const complied = await compileCSS(filename + '.css', code)
s.overwrite(start, end, complied.code)
}

html = s.toString()
Expand Down

0 comments on commit 43c3dce

Please sign in to comment.