diff --git a/packages/playground/css/__tests__/css.spec.ts b/packages/playground/css/__tests__/css.spec.ts index 8025d5766656b5..f46d519907e963 100644 --- a/packages/playground/css/__tests__/css.spec.ts +++ b/packages/playground/css/__tests__/css.spec.ts @@ -266,3 +266,8 @@ test('Url separation', async () => { ) } }) + +test('inlined', async () => { + // should not insert css + expect(await getColor('.inlined')).toBe('black') +}) diff --git a/packages/playground/css/index.html b/packages/playground/css/index.html index 306f2c5169599c..557e7e4cd8416e 100644 --- a/packages/playground/css/index.html +++ b/packages/playground/css/index.html @@ -86,6 +86,9 @@

CSS

Url separation preservation: should have valid background-image

+ +

Inlined import - this should NOT be red.

+

 
 
 
diff --git a/packages/playground/css/inlined.css b/packages/playground/css/inlined.css
new file mode 100644
index 00000000000000..f34e383a1bbfcb
--- /dev/null
+++ b/packages/playground/css/inlined.css
@@ -0,0 +1,3 @@
+.inlined {
+  color: green;
+}
\ No newline at end of file
diff --git a/packages/playground/css/main.js b/packages/playground/css/main.js
index d8073a86981f0a..0c29abbbd4efac 100644
--- a/packages/playground/css/main.js
+++ b/packages/playground/css/main.js
@@ -47,3 +47,7 @@ import('./async')
 if (import.meta.env.DEV) {
   import('./async-treeshaken')
 }
+
+// inlined
+import inlined from './inlined.css?inline'
+text('.inlined-code', inlined)
diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts
index 8b3108ab8b6b80..90397083a6ecb9 100644
--- a/packages/vite/src/node/plugins/css.ts
+++ b/packages/vite/src/node/plugins/css.ts
@@ -86,6 +86,7 @@ export const cssLangRE = new RegExp(cssLangs)
 const cssModuleRE = new RegExp(`\\.module${cssLangs}`)
 const directRequestRE = /(\?|&)direct\b/
 const commonjsProxyRE = /\?commonjs-proxy/
+const inlineRE = /(\?|&)inline\b/
 
 const enum PreprocessLang {
   less = 'less',
@@ -190,36 +191,37 @@ export function cssPlugin(config: ResolvedConfig): Plugin {
       if (server) {
         // server only logic for handling CSS @import dependency hmr
         const { moduleGraph } = server
-        const thisModule = moduleGraph.getModuleById(id)!
-
-        // CSS modules cannot self-accept since it exports values
-        const isSelfAccepting = !modules
-        if (deps) {
-          // record deps in the module graph so edits to @import css can trigger
-          // main import to hot update
-          const depModules = new Set()
-          for (const file of deps) {
-            depModules.add(
-              cssLangRE.test(file)
-                ? moduleGraph.createFileOnlyEntry(file)
-                : await moduleGraph.ensureEntryFromUrl(
-                    await fileToUrl(file, config, this)
-                  )
+        const thisModule = moduleGraph.getModuleById(id)
+        if (thisModule) {
+          // CSS modules cannot self-accept since it exports values
+          const isSelfAccepting = !modules
+          if (deps) {
+            // record deps in the module graph so edits to @import css can trigger
+            // main import to hot update
+            const depModules = new Set()
+            for (const file of deps) {
+              depModules.add(
+                cssLangRE.test(file)
+                  ? moduleGraph.createFileOnlyEntry(file)
+                  : await moduleGraph.ensureEntryFromUrl(
+                      await fileToUrl(file, config, this)
+                    )
+              )
+            }
+            moduleGraph.updateModuleInfo(
+              thisModule,
+              depModules,
+              // The root CSS proxy module is self-accepting and should not
+              // have an explicit accept list
+              new Set(),
+              isSelfAccepting
             )
+            for (const file of deps) {
+              this.addWatchFile(file)
+            }
+          } else {
+            thisModule.isSelfAccepting = isSelfAccepting
           }
-          moduleGraph.updateModuleInfo(
-            thisModule,
-            depModules,
-            // The root CSS proxy module is self-accepting and should not
-            // have an explicit accept list
-            new Set(),
-            isSelfAccepting
-          )
-          for (const file of deps) {
-            this.addWatchFile(file)
-          }
-        } else {
-          thisModule.isSelfAccepting = isSelfAccepting
         }
       }
 
@@ -255,11 +257,12 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
       hasEmitted = false
     },
 
-    transform(css, id, ssr) {
+    async transform(css, id, ssr) {
       if (!cssLangRE.test(id) || commonjsProxyRE.test(id)) {
         return
       }
 
+      const inlined = inlineRE.test(id)
       const modules = cssModulesCache.get(config)!.get(id)
       const modulesCode =
         modules && dataToEsm(modules, { namedExports: true, preferConst: true })
@@ -272,6 +275,9 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
           if (ssr) {
             return modulesCode || `export default ${JSON.stringify(css)}`
           }
+          if (inlined) {
+            return `export default ${JSON.stringify(css)}`
+          }
           return [
             `import { updateStyle, removeStyle } from ${JSON.stringify(
               path.posix.join(config.base, CLIENT_PUBLIC_PATH)
@@ -289,7 +295,11 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
       // build CSS handling ----------------------------------------------------
 
       // record css
-      styles.set(id, css)
+      if (!inlined) {
+        styles.set(id, css)
+      } else {
+        css = await minifyCSS(css, config)
+      }
 
       return {
         code: modulesCode || `export default ${JSON.stringify(css)}`,