+ CSS @import
+
+ <style @import > this should be red
+
+
+ <script @import > this should be green
+
+
+
+
+
+
diff --git a/playground/css-@import/imported.css b/playground/css-@import/imported.css
new file mode 100644
index 00000000000000..954e5708f09d0c
--- /dev/null
+++ b/playground/css-@import/imported.css
@@ -0,0 +1,3 @@
+.script-at-import {
+ color: green;
+}
diff --git a/playground/css-@import/testCssAtImportFromScript.css b/playground/css-@import/testCssAtImportFromScript.css
new file mode 100644
index 00000000000000..83dcc223c86630
--- /dev/null
+++ b/playground/css-@import/testCssAtImportFromScript.css
@@ -0,0 +1 @@
+@import './imported.css'
diff --git a/playground/css-@import/testCssAtImportFromStyle.css b/playground/css-@import/testCssAtImportFromStyle.css
new file mode 100644
index 00000000000000..1557d3b3c0d5a5
--- /dev/null
+++ b/playground/css-@import/testCssAtImportFromStyle.css
@@ -0,0 +1,3 @@
+.sfc-style-at-import {
+ color: red;
+}
diff --git a/src/node/build/buildPluginCss.ts b/src/node/build/buildPluginCss.ts
index a5441c0a497e22..319674f4eb0177 100644
--- a/src/node/build/buildPluginCss.ts
+++ b/src/node/build/buildPluginCss.ts
@@ -34,7 +34,7 @@ export const createBuildCssPlugin = (
const result = await compileCss(root, id, {
id: '',
source: css,
- filename: path.basename(id),
+ filename: id,
scoped: false,
modules: id.endsWith('.module.css'),
preprocessLang: id.replace(cssPreprocessLangRE, '$2') as any
diff --git a/src/node/server/serverPluginCss.ts b/src/node/server/serverPluginCss.ts
index 3cd4c63ed3e368..da5356ab3c0b1d 100644
--- a/src/node/server/serverPluginCss.ts
+++ b/src/node/server/serverPluginCss.ts
@@ -7,7 +7,9 @@ import { srcImportMap, vueCache } from './serverPluginVue'
import {
codegenCss,
compileCss,
+ cssImportMap,
cssPreprocessLangRE,
+ getCssImportBoundaries,
rewriteCssUrls
} from '../utils/cssUtils'
import qs from 'querystring'
@@ -55,7 +57,11 @@ export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {
const publicPath = resolver.fileToRequest(filePath)
/** filter unused files */
- if (!processedCSS.has(publicPath) && !srcImportMap.has(filePath)) {
+ if (
+ !cssImportMap.has(filePath) &&
+ !processedCSS.has(publicPath) &&
+ !srcImportMap.has(filePath)
+ ) {
return debugCSS(
`${basename(publicPath)} has changed, but it is not currently in use`
)
@@ -66,45 +72,69 @@ export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {
// it cannot be handled as simple css import because it may be scoped
const styleImport = srcImportMap.get(filePath)
vueCache.del(filePath)
- const publicPath = cleanUrl(styleImport)
- const index = qs.parse(styleImport.split('?', 2)[1]).index
- console.log(
- chalk.green(`[vite:hmr] `) + `${publicPath} updated. (style)`
- )
- watcher.send({
- type: 'style-update',
- path: `${publicPath}?type=style&index=${index}`,
- timestamp: Date.now()
- })
+ vueStyleUpdate(styleImport)
return
}
// handle HMR for module.css
- // it cannot process with normal css, the class which in module.css maybe removed
+ // it cannot be handled as normal css because the js exports may change
if (filePath.endsWith('.module.css')) {
- watcher.handleJSReload(filePath, Date.now())
+ moduleCssUpdate(filePath)
return
}
- // bust process cache
- processedCSS.delete(publicPath)
-
- watcher.send({
- type: 'style-update',
- path: publicPath,
- timestamp: Date.now()
- })
+ const boundaries = getCssImportBoundaries(filePath)
+ if (boundaries.size) {
+ for (let boundary of boundaries) {
+ if (boundary.includes('.module')) {
+ moduleCssUpdate(boundary)
+ } else if (boundary.includes('.vue')) {
+ vueCache.del(cleanUrl(boundary))
+ vueStyleUpdate(resolver.fileToRequest(boundary))
+ } else {
+ normalCssUpdate(resolver.fileToRequest(boundary))
+ }
+ }
+ return
+ }
+ // no boundaries
+ normalCssUpdate(publicPath)
}
})
- async function processCss(root: string, ctx: Context) {
- let css = (await readBody(ctx.body))!
+ function vueStyleUpdate(styleImport: string) {
+ const publicPath = cleanUrl(styleImport)
+ const index = qs.parse(styleImport.split('?', 2)[1]).index
+ console.log(chalk.green(`[vite:hmr] `) + `${publicPath} updated. (style)`)
+ watcher.send({
+ type: 'style-update',
+ path: `${publicPath}?type=style&index=${index}`,
+ timestamp: Date.now()
+ })
+ }
+ function moduleCssUpdate(filePath: string) {
+ watcher.handleJSReload(filePath)
+ }
+
+ function normalCssUpdate(publicPath: string) {
+ // bust process cache
+ processedCSS.delete(publicPath)
+
+ watcher.send({
+ type: 'style-update',
+ path: publicPath,
+ timestamp: Date.now()
+ })
+ }
+
+ async function processCss(root: string, ctx: Context) {
+ const css = (await readBody(ctx.body))!
const result = await compileCss(root, ctx.path, {
id: '',
source: css,
filename: resolver.requestToFile(ctx.path),
scoped: false,
- modules: ctx.path.endsWith('.module.css'),
+ modules: ctx.path.includes('.module'),
preprocessLang: ctx.path.replace(cssPreprocessLangRE, '$2') as any
})
diff --git a/src/node/server/serverPluginVue.ts b/src/node/server/serverPluginVue.ts
index fa162579dcd3a5..6ba6e0f2d2d51a 100644
--- a/src/node/server/serverPluginVue.ts
+++ b/src/node/server/serverPluginVue.ts
@@ -514,10 +514,9 @@ async function compileSFCStyle(
const start = Date.now()
const { generateCodeFrame } = resolveCompiler(root)
-
const result = (await compileCss(root, publicPath, {
source: style.content,
- filename: filePath,
+ filename: filePath + `?type=style&index=${index}`,
id: ``, // will be computed in compileCss
scoped: style.scoped != null,
modules: style.module != null,
diff --git a/src/node/utils/cssUtils.ts b/src/node/utils/cssUtils.ts
index cbccd2d7746e40..abd066257b8eff 100644
--- a/src/node/utils/cssUtils.ts
+++ b/src/node/utils/cssUtils.ts
@@ -54,15 +54,24 @@ export async function compileCss(
}: SFCAsyncStyleCompileOptions
): Promise