Skip to content

Commit

Permalink
feat: support HMR for css preprocessor @import (#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
underfin authored Jul 16, 2020
1 parent 23a0053 commit cc1e8e8
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 25 deletions.
3 changes: 3 additions & 0 deletions playground/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<TestCssModules />
<TestCssAtImport />
<TestPreprocessors />
<TestScssAtImport/>
<TestAssets />
<TestSrcImport />
<TestJsonImport />
Expand Down Expand Up @@ -46,6 +47,7 @@ import TestJsx from './jsx/TestJsx.vue'
import TestAlias from './alias/TestAlias.vue'
import TestTransform from './transform/TestTransform.vue'
import TestCssAtImport from './css-@import/TestCssAtImport.vue'
import TestScssAtImport from './css-@import/TestSCssAtImport.vue'
import TestCustomBlocks from './custom-blocks/TestCustomBlocks.vue'
import TestOptimizeLink from './optimize-linked/TestOptimizeLink.vue'
import TestModuleResolve from './resolve/TestModuleResolve.vue'
Expand All @@ -67,6 +69,7 @@ export default {
TestCssModules,
TestPreprocessors,
TestCssAtImport,
TestScssAtImport,
TestSrcImport,
TestAssets,
TestJsonImport,
Expand Down
22 changes: 22 additions & 0 deletions playground/css-@import/TestScssAtImport.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<template>
<h2>CSS Preprocessor @import</h2>
<div class="sfc-style-scss-at-import">
&lt;style lang="scss" @import &gt; this should be red
</div>
<div class="script-scss-at-import">
&lt;script scss @import &gt; this should be green
</div>
</template>

<style lang="scss" scoped>
@import './testScssAtImportFromStyle.scss';
.sfc-style-scss-at-import {
color: $colorSfc;
}
</style>

<script>
import './testScssAtImportFromScript.scss'
export default {}
</script>
1 change: 1 addition & 0 deletions playground/css-@import/testCssAtImportFromScript.css
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
@import './imported.css'

1 change: 1 addition & 0 deletions playground/css-@import/testScss.imported.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$colorScript: green;
4 changes: 4 additions & 0 deletions playground/css-@import/testScssAtImportFromScript.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@import './testScss.imported.scss';
.script-scss-at-import {
color: $colorScript;
}
2 changes: 2 additions & 0 deletions playground/css-@import/testScssAtImportFromStyle.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// single comment is not support by css
$colorSfc: red;
10 changes: 7 additions & 3 deletions src/node/server/serverPluginCss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import { cleanUrl, isImportRequest, readBody } from '../utils'
import { srcImportMap, vueCache } from './serverPluginVue'
import {
compileCss,
cssImportMap,
cssImporterMap,
cssPreprocessLangRE,
getCssImportBoundaries,
recordCssImportChain,
rewriteCssUrls,
isCSSRequest
} from '../utils/cssUtils'
Expand Down Expand Up @@ -44,7 +45,7 @@ export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {

/** filter unused files */
if (
!cssImportMap.has(filePath) &&
!cssImporterMap.has(filePath) &&
!processedCSS.has(publicPath) &&
!srcImportMap.has(filePath)
) {
Expand Down Expand Up @@ -135,10 +136,11 @@ export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {
}

const css = (await readBody(ctx.body))!
const filePath = resolver.requestToFile(ctx.path)
const result = await compileCss(root, ctx.path, {
id: '',
source: css,
filename: resolver.requestToFile(ctx.path),
filename: filePath,
scoped: false,
modules: ctx.path.includes('.module'),
preprocessLang: ctx.path.replace(cssPreprocessLangRE, '$2') as any,
Expand All @@ -151,6 +153,8 @@ export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {
return res
}

recordCssImportChain(result.dependencies, filePath)

if (result.errors.length) {
console.error(`[vite] error applying css transforms: `)
result.errors.forEach(console.error)
Expand Down
11 changes: 9 additions & 2 deletions src/node/server/serverPluginVue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ import { transform } from '../esbuildService'
import { InternalResolver } from '../resolver'
import { seenUrls } from './serverPluginServeStatic'
import { codegenCss } from './serverPluginCss'
import { compileCss, rewriteCssUrls } from '../utils/cssUtils'
import {
compileCss,
recordCssImportChain,
rewriteCssUrls
} from '../utils/cssUtils'
import { parse } from '../utils/babelParse'
import MagicString from 'magic-string'
import { resolveImport } from './serverPluginModuleRewrite'
Expand Down Expand Up @@ -609,9 +613,10 @@ async function compileSFCStyle(
const start = Date.now()

const { generateCodeFrame } = resolveCompiler(root)
const resource = filePath + `?type=style&index=${index}`
const result = (await compileCss(root, publicPath, {
source: style.content,
filename: filePath + `?type=style&index=${index}`,
filename: resource,
id: ``, // will be computed in compileCss
scoped: style.scoped != null,
vars: style.vars != null,
Expand All @@ -620,6 +625,8 @@ async function compileSFCStyle(
preprocessOptions
})) as SFCStyleCompileResults

recordCssImportChain(result.dependencies, resource)

if (result.errors.length) {
console.error(chalk.red(`\n[vite] SFC style compilation error: `))
result.errors.forEach((e: any) => {
Expand Down
56 changes: 36 additions & 20 deletions src/node/utils/cssUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export async function compileCss(
plugins: postcssPlugins
} = await resolvePostcssOptions(root, isBuild)

const res = await compileStyleAsync({
return await compileStyleAsync({
source,
filename,
id: `data-v-${id}`,
Expand All @@ -106,22 +106,6 @@ export async function compileCss(
postcssOptions,
postcssPlugins
})

// record css import dependencies
if (res.rawResult) {
res.rawResult.messages.forEach((msg) => {
let { type, file, parent } = msg
if (type === 'dependency') {
if (cssImportMap.has(file)) {
cssImportMap.get(file)!.add(parent)
} else {
cssImportMap.set(file, new Set([parent]))
}
}
})
}

return res
}

// postcss-load-config doesn't expose Result type
Expand Down Expand Up @@ -163,7 +147,11 @@ export async function resolvePostcssOptions(root: string, isBuild: boolean) {
}
}

export const cssImportMap = new Map<
export const cssImporterMap = new Map<
string /*filePath*/,
Set<string /*filePath*/>
>()
export const cssImporteeMap = new Map<
string /*filePath*/,
Set<string /*filePath*/>
>()
Expand All @@ -172,13 +160,41 @@ export function getCssImportBoundaries(
filePath: string,
boundaries = new Set<string>()
) {
if (!cssImportMap.has(filePath)) {
if (!cssImporterMap.has(filePath)) {
return boundaries
}
const importers = cssImportMap.get(filePath)!
const importers = cssImporterMap.get(filePath)!
for (const importer of importers) {
boundaries.add(importer)
getCssImportBoundaries(importer, boundaries)
}
return boundaries
}

export function recordCssImportChain(
dependencies: Set<string>,
filePath: string
) {
const preImportees = cssImporteeMap.get(filePath)
// if import code change, should removed unused previous importee
if (preImportees) {
for (const preImportee of preImportees) {
if (!dependencies.has(preImportee)) {
const importers = cssImporterMap.get(preImportee)
if (importers) {
importers.delete(filePath)
}
}
}
}

dependencies.forEach((dependency) => {
if (cssImporterMap.has(dependency)) {
cssImporterMap.get(dependency)!.add(filePath)
} else {
cssImporterMap.set(dependency, new Set([filePath]))
}
})

cssImporteeMap.set(filePath, dependencies)
}
23 changes: 23 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,29 @@ describe('vite', () => {
}
})

test('CSS preprocessor @import', async () => {
const el = await page.$('.script-scss-at-import')
expect(await getComputedColor(el)).toBe('rgb(0, 128, 0)')
if (!isBuild) {
await updateFile('css-@import/testScss.imported.scss', (content) =>
content.replace('green', 'rgb(0, 0, 0)')
)
await expectByPolling(() => getComputedColor(el), 'rgb(0, 0, 0)')
}
})

test('SFC <style lang="sass"> w/ @import', async () => {
const el = await page.$('.sfc-style-scss-at-import')
expect(await getComputedColor(el)).toBe('rgb(255, 0, 0)')
if (!isBuild) {
await updateFile(
'css-@import/testSCssAtImportFromStyle.scss',
(content) => content.replace('red', 'rgb(0, 0, 0)')
)
await expectByPolling(() => getComputedColor(el), 'rgb(0, 0, 0)')
}
})

test('import *.module.css', async () => {
const el = await page.$('.css-modules-import')
expect(await getComputedColor(el)).toBe('rgb(255, 140, 0)')
Expand Down

0 comments on commit cc1e8e8

Please sign in to comment.