diff --git a/packages/playground/assets/__tests__/assets.spec.ts b/packages/playground/assets/__tests__/assets.spec.ts
index f53c783c52b606..e08de24265e24a 100644
--- a/packages/playground/assets/__tests__/assets.spec.ts
+++ b/packages/playground/assets/__tests__/assets.spec.ts
@@ -263,6 +263,7 @@ if (isBuild) {
}
})
}
+
describe('css and assets in css in build watch', () => {
if (isBuild) {
test('css will not be lost and css does not contain undefined', async () => {
@@ -271,7 +272,26 @@ describe('css and assets in css in build watch', () => {
const cssFile = findAssetFile(/index\.\w+\.css$/, 'foo')
expect(cssFile).not.toBe('')
expect(cssFile).not.toMatch(/undefined/)
- watcher?.close()
+ })
+
+ test('import module.css', async () => {
+ expect(await getColor('#foo')).toBe('red')
+ editFile(
+ 'css/foo.module.css',
+ (code) => code.replace('red', 'blue'),
+ true
+ )
+ await notifyRebuildComplete(watcher)
+ await page.reload()
+ expect(await getColor('#foo')).toBe('blue')
+ })
+
+ test('import with raw query', async () => {
+ expect(await page.textContent('.raw-query')).toBe('foo')
+ editFile('static/foo.txt', (code) => code.replace('foo', 'zoo'), true)
+ await notifyRebuildComplete(watcher)
+ await page.reload()
+ expect(await page.textContent('.raw-query')).toBe('zoo')
})
}
})
diff --git a/packages/playground/assets/css/foo.module.css b/packages/playground/assets/css/foo.module.css
new file mode 100644
index 00000000000000..196612f252d254
--- /dev/null
+++ b/packages/playground/assets/css/foo.module.css
@@ -0,0 +1,3 @@
+.foo-module {
+ color: red;
+}
diff --git a/packages/playground/assets/index.html b/packages/playground/assets/index.html
index 7534ecbe1677bf..b0ec76f5483b6f 100644
--- a/packages/playground/assets/index.html
+++ b/packages/playground/assets/index.html
@@ -212,6 +212,10 @@
@import
@import CSS from publicDir should load (this should be red)
+import module css
+
+
+
@@ -268,6 +272,12 @@
document.querySelector('.import-meta-url-img-comma-nl').src =
metaUrlWithCommaNL
+ import classNames from './css/foo.module.css'
+ document.querySelector('#foo').className = classNames['foo-module']
+
+ import someString from './static/foo.txt?raw'
+ document.querySelector('.raw-query').textContent = someString
+
const metaUrlNonExistent = new URL('non-existent', import.meta.url).pathname
text('.non-existent-import-meta-url', metaUrlNonExistent)
diff --git a/packages/playground/assets/static/foo.txt b/packages/playground/assets/static/foo.txt
new file mode 100644
index 00000000000000..19102815663d23
--- /dev/null
+++ b/packages/playground/assets/static/foo.txt
@@ -0,0 +1 @@
+foo
\ No newline at end of file
diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts
index 3541cc377dc411..ff03352a20d7a7 100644
--- a/packages/vite/src/node/build.ts
+++ b/packages/vite/src/node/build.ts
@@ -39,6 +39,7 @@ import { getDepsCacheDir, findKnownImports } from './optimizer'
import { assetImportMetaUrlPlugin } from './plugins/assetImportMetaUrl'
import { loadFallbackPlugin } from './plugins/loadFallback'
import { watchPackageDataPlugin } from './packages'
+import { ensureWatchPlugin } from './plugins/ensureWatch'
export interface BuildOptions {
/**
@@ -308,6 +309,7 @@ export function resolveBuildPlugins(config: ResolvedConfig): {
return {
pre: [
+ ...(options.watch ? [ensureWatchPlugin()] : []),
watchPackageDataPlugin(config),
commonjsPlugin(options.commonjsOptions),
dataURIPlugin(),
diff --git a/packages/vite/src/node/plugins/ensureWatch.ts b/packages/vite/src/node/plugins/ensureWatch.ts
new file mode 100644
index 00000000000000..30a6fb3d6df819
--- /dev/null
+++ b/packages/vite/src/node/plugins/ensureWatch.ts
@@ -0,0 +1,17 @@
+import type { Plugin } from '../plugin'
+import { cleanUrl, queryRE } from '../utils'
+
+/**
+ * plugin to ensure rollup can watch correctly.
+ */
+export function ensureWatchPlugin(): Plugin {
+ return {
+ name: 'vite:ensure-watch',
+ load(id) {
+ if (queryRE.test(id)) {
+ this.addWatchFile(cleanUrl(id))
+ }
+ return null
+ }
+ }
+}
diff --git a/packages/vite/src/node/plugins/index.ts b/packages/vite/src/node/plugins/index.ts
index d294233b92ae17..2d34b99aebf1c5 100644
--- a/packages/vite/src/node/plugins/index.ts
+++ b/packages/vite/src/node/plugins/index.ts
@@ -17,6 +17,7 @@ import { preAliasPlugin } from './preAlias'
import { definePlugin } from './define'
import { ssrRequireHookPlugin } from './ssrRequireHook'
import { workerImportMetaUrlPlugin } from './workerImportMetaUrl'
+import { ensureWatchPlugin } from './ensureWatch'
import { metadataPlugin } from './metadata'
export async function resolvePlugins(
@@ -26,12 +27,14 @@ export async function resolvePlugins(
postPlugins: Plugin[]
): Promise {
const isBuild = config.command === 'build'
+ const isWatch = isBuild && !!config.build.watch
const buildPlugins = isBuild
? (await import('../build')).resolveBuildPlugins(config)
: { pre: [], post: [] }
return [
+ isWatch ? ensureWatchPlugin() : null,
isBuild ? metadataPlugin() : null,
isBuild ? null : preAliasPlugin(),
aliasPlugin({ entries: config.resolve.alias }),
diff --git a/scripts/jestPerTestSetup.ts b/scripts/jestPerTestSetup.ts
index 150c02eed5b76c..fcdca77ee9a6eb 100644
--- a/scripts/jestPerTestSetup.ts
+++ b/scripts/jestPerTestSetup.ts
@@ -175,6 +175,7 @@ afterAll(async () => {
global.serverLogs = []
await global.page?.close()
await server?.close()
+ global.watcher?.close()
const beforeAllErr = getBeforeAllError()
if (beforeAllErr) {
throw beforeAllErr
@@ -200,7 +201,7 @@ function startStaticServer(config?: InlineConfig): Promise {
}
// start static file server
- const serve = sirv(resolve(rootDir, 'dist'))
+ const serve = sirv(resolve(rootDir, 'dist'), { dev: !!config?.build?.watch })
const httpServer = (server = http.createServer((req, res) => {
if (req.url === '/ping') {
res.statusCode = 200