diff --git a/packages/playground/js-sourcemap/__tests__/build.spec.ts b/packages/playground/js-sourcemap/__tests__/build.spec.ts
new file mode 100644
index 00000000000000..e36c1f52d2c1f8
--- /dev/null
+++ b/packages/playground/js-sourcemap/__tests__/build.spec.ts
@@ -0,0 +1,13 @@
+import { isBuild } from 'testUtils'
+
+if (isBuild) {
+ test('should not output sourcemap warning (#4939)', () => {
+ serverLogs.forEach((log) => {
+ expect(log).not.toMatch('Sourcemap is likely to be incorrect')
+ })
+ })
+} else {
+ test('this file only includes test for build', () => {
+ expect(true).toBe(true)
+ })
+}
diff --git a/packages/playground/js-sourcemap/__tests__/serve.spec.ts b/packages/playground/js-sourcemap/__tests__/serve.spec.ts
new file mode 100644
index 00000000000000..a1ffdddc37ecd5
--- /dev/null
+++ b/packages/playground/js-sourcemap/__tests__/serve.spec.ts
@@ -0,0 +1,44 @@
+import { URL } from 'url'
+import {
+ extractSourcemap,
+ formatSourcemapForSnapshot,
+ isBuild
+} from 'testUtils'
+
+if (!isBuild) {
+ test('js', async () => {
+ const res = await page.request.get(new URL('./foo.js', page.url()).href)
+ const js = await res.text()
+ const lines = js.split('\n')
+ expect(lines[lines.length - 1].includes('//')).toBe(false) // expect no sourcemap
+ })
+
+ test('ts', async () => {
+ const res = await page.request.get(new URL('./bar.ts', page.url()).href)
+ const js = await res.text()
+ const map = extractSourcemap(js)
+ expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(`
+ Object {
+ "mappings": "AAAO,aAAM,MAAM;",
+ "sources": Array [
+ "/root/bar.ts",
+ ],
+ "sourcesContent": Array [
+ "export const bar = 'bar'
+ ",
+ ],
+ "version": 3,
+ }
+ `)
+ })
+
+ test('should not output missing source file warning', () => {
+ serverLogs.forEach((log) => {
+ expect(log).not.toMatch(/Sourcemap for .+ points to missing source files/)
+ })
+ })
+} else {
+ test('this file only includes test for serve', () => {
+ expect(true).toBe(true)
+ })
+}
diff --git a/packages/playground/js-sourcemap/bar.ts b/packages/playground/js-sourcemap/bar.ts
new file mode 100644
index 00000000000000..1fc11814f22e80
--- /dev/null
+++ b/packages/playground/js-sourcemap/bar.ts
@@ -0,0 +1 @@
+export const bar = 'bar'
diff --git a/packages/playground/js-sourcemap/foo.js b/packages/playground/js-sourcemap/foo.js
new file mode 100644
index 00000000000000..cb356468240d50
--- /dev/null
+++ b/packages/playground/js-sourcemap/foo.js
@@ -0,0 +1 @@
+export const foo = 'foo'
diff --git a/packages/playground/js-sourcemap/index.html b/packages/playground/js-sourcemap/index.html
new file mode 100644
index 00000000000000..025b161011a3fa
--- /dev/null
+++ b/packages/playground/js-sourcemap/index.html
@@ -0,0 +1,6 @@
+
+
JS Sourcemap
+
+
+
+
diff --git a/packages/playground/js-sourcemap/package.json b/packages/playground/js-sourcemap/package.json
new file mode 100644
index 00000000000000..e5a97aea80830f
--- /dev/null
+++ b/packages/playground/js-sourcemap/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "test-js-sourcemap",
+ "private": true,
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "debug": "node --inspect-brk ../../vite/bin/vite",
+ "preview": "vite preview"
+ }
+}
diff --git a/packages/playground/js-sourcemap/vite.config.js b/packages/playground/js-sourcemap/vite.config.js
new file mode 100644
index 00000000000000..bc9d1748cab964
--- /dev/null
+++ b/packages/playground/js-sourcemap/vite.config.js
@@ -0,0 +1,8 @@
+/**
+ * @type {import('vite').UserConfig}
+ */
+module.exports = {
+ build: {
+ sourcemap: true
+ }
+}
diff --git a/packages/playground/legacy/__tests__/legacy.spec.ts b/packages/playground/legacy/__tests__/legacy.spec.ts
index b8025694437502..65bd39ff32b1d1 100644
--- a/packages/playground/legacy/__tests__/legacy.spec.ts
+++ b/packages/playground/legacy/__tests__/legacy.spec.ts
@@ -83,4 +83,8 @@ if (isBuild) {
test('should emit css file', async () => {
expect(listAssets().some((filename) => filename.endsWith('.css')))
})
+
+ test('includes structuredClone polyfill which is supported after core-js v3', () => {
+ expect(findAssetFile(/polyfills-legacy/)).toMatch('"structuredClone"')
+ })
}
diff --git a/packages/playground/legacy/__tests__/ssr/serve.js b/packages/playground/legacy/__tests__/ssr/serve.js
index df43f180afb188..c7ef2ed3520e53 100644
--- a/packages/playground/legacy/__tests__/ssr/serve.js
+++ b/packages/playground/legacy/__tests__/ssr/serve.js
@@ -2,8 +2,9 @@
// this is automtically detected by scripts/jestPerTestSetup.ts and will replace
// the default e2e test serve behavior
const path = require('path')
+const { ports } = require('../../../testUtils')
-const port = (exports.port = 9527)
+const port = (exports.port = ports['legacy/ssr'])
/**
* @param {string} root
diff --git a/packages/playground/legacy/index.html b/packages/playground/legacy/index.html
index bdc2feac6b4fbe..d481766463cd4f 100644
--- a/packages/playground/legacy/index.html
+++ b/packages/playground/legacy/index.html
@@ -1,6 +1,7 @@
+
diff --git a/packages/playground/legacy/main.js b/packages/playground/legacy/main.js
index b05acf439bdff8..31579b4717810d 100644
--- a/packages/playground/legacy/main.js
+++ b/packages/playground/legacy/main.js
@@ -21,6 +21,12 @@ text('#env', `is legacy: ${isLegacy}`)
// Iterators
text('#iterators', [...new Set(['hello'])].join(''))
+// structuredClone is supported core.js v3.20.0+
+text(
+ '#features-after-corejs-3',
+ JSON.stringify(structuredClone({ foo: 'foo' }))
+)
+
// babel-helpers
// Using `String.raw` to inject `@babel/plugin-transform-template-literals`
// helpers.
diff --git a/packages/playground/lib/__tests__/serve.js b/packages/playground/lib/__tests__/serve.js
index 15c64de40276d1..eac6980286af52 100644
--- a/packages/playground/lib/__tests__/serve.js
+++ b/packages/playground/lib/__tests__/serve.js
@@ -5,8 +5,9 @@
const path = require('path')
const http = require('http')
const sirv = require('sirv')
+const { ports } = require('../../testUtils')
-const port = (exports.port = 9527)
+const port = (exports.port = ports.lib)
/**
* @param {string} root
diff --git a/packages/playground/optimize-missing-deps/__test__/serve.js b/packages/playground/optimize-missing-deps/__test__/serve.js
index 9f293024f83913..89a6ce3593cd0e 100644
--- a/packages/playground/optimize-missing-deps/__test__/serve.js
+++ b/packages/playground/optimize-missing-deps/__test__/serve.js
@@ -3,8 +3,9 @@
// the default e2e test serve behavior
const path = require('path')
+const { ports } = require('../../testUtils')
-const port = (exports.port = 9529)
+const port = (exports.port = ports['optimize-missing-deps'])
/**
* @param {string} root
diff --git a/packages/playground/package.json b/packages/playground/package.json
index 58ef368099e82f..75b1d15d299319 100644
--- a/packages/playground/package.json
+++ b/packages/playground/package.json
@@ -3,6 +3,7 @@
"private": true,
"version": "1.0.0",
"devDependencies": {
+ "convert-source-map": "^1.8.0",
"css-color-names": "^1.0.1"
}
}
diff --git a/packages/playground/resolve/__tests__/resolve.spec.ts b/packages/playground/resolve/__tests__/resolve.spec.ts
index b64da138033fc0..46f8f6138b39a4 100644
--- a/packages/playground/resolve/__tests__/resolve.spec.ts
+++ b/packages/playground/resolve/__tests__/resolve.spec.ts
@@ -17,7 +17,10 @@ test('deep import with exports field', async () => {
})
test('deep import with query with exports field', async () => {
- expect(await page.textContent('.exports-deep-query')).not.toMatch('fail')
+ // since it is imported with `?url` it should return a url
+ expect(await page.textContent('.exports-deep-query')).toMatch(
+ isBuild ? /base64/ : '/exports-path/deep.json'
+ )
})
test('deep import with exports field + exposed dir', async () => {
@@ -58,6 +61,18 @@ test('dont add extension to directory name (./dir-with-ext.js/index.js)', async
expect(await page.textContent('.dir-with-ext')).toMatch('[success]')
})
+test('resolve to the `browser` field instead of `module` when the importer is a `require` call', async () => {
+ expect(
+ await page.textContent('.require-pkg-with-browser-and-module-field')
+ ).toMatch('[success]')
+})
+
+test('resolve to the `main` field instead of `module` when the importer is a `require` call', async () => {
+ expect(await page.textContent('.require-pkg-with-esm-entries')).toMatch(
+ '[success]'
+ )
+})
+
test('a ts module can import another ts module using its corresponding js file name', async () => {
expect(await page.textContent('.ts-extension')).toMatch('[success]')
})
diff --git a/packages/playground/resolve/index.html b/packages/playground/resolve/index.html
index c0569345d86837..2478c89b495f49 100644
--- a/packages/playground/resolve/index.html
+++ b/packages/playground/resolve/index.html
@@ -58,6 +58,18 @@
Resolve file name containing dot
Browser Field
fail
+
+ Resolve to the `browser` field instead of `module` when the importer is a
+ `require` call
+
+
fail
+
+
+ Resolve to the `main` field instead of `module` when the importer is a
+ `require` call
+
+
fail
+
CSS Entry
@@ -168,10 +180,11 @@
resolve package that contains # in path
import e from 'resolve-browser-field/ext-index/index.js'
import f from 'resolve-browser-field/ext-index'
import g from 'resolve-browser-field/no-ext-index/index.js' // no substitution
+ import h from 'resolve-browser-field/no-ext?query'
import { ra, rb, rc, rd, re, rf, rg } from 'resolve-browser-field/relative'
- const success = [main, a, c, d, e, f, ra, rc, rd, re, rf]
+ const success = [main, a, c, d, e, f, h, ra, rc, rd, re, rf]
const noSuccess = [b, g, rb, rg]
if (
@@ -181,6 +194,12 @@
resolve package that contains # in path
text('.browser', main)
}
+ import { msg as requireBrowserMsg } from 'require-pkg-with-browser-and-module-field'
+ text('.require-pkg-with-browser-and-module-field', requireBrowserMsg)
+
+ import { msg as requireMainMsg } from 'require-pkg-with-esm-entries'
+ text('.require-pkg-with-esm-entries', requireMainMsg)
+
import { msg as customExtMsg } from './custom-ext'
text('.custom-ext', customExtMsg)
diff --git a/packages/playground/resolve/package.json b/packages/playground/resolve/package.json
index 5e0f53b4c8468a..4b8d497b3dbb27 100644
--- a/packages/playground/resolve/package.json
+++ b/packages/playground/resolve/package.json
@@ -12,6 +12,8 @@
"@babel/runtime": "^7.16.0",
"es5-ext": "0.10.53",
"normalize.css": "^8.0.1",
+ "require-pkg-with-browser-and-module-field": "link:./require-pkg-with-browser-and-module-field",
+ "require-pkg-with-esm-entries": "link:./require-pkg-with-esm-entries",
"resolve-browser-field": "link:./browser-field",
"resolve-custom-condition": "link:./custom-condition",
"resolve-custom-main-field": "link:./custom-main-field",
diff --git a/packages/playground/resolve/require-pkg-with-browser-and-module-field/dep.cjs b/packages/playground/resolve/require-pkg-with-browser-and-module-field/dep.cjs
new file mode 100644
index 00000000000000..3fb20b76d48b79
--- /dev/null
+++ b/packages/playground/resolve/require-pkg-with-browser-and-module-field/dep.cjs
@@ -0,0 +1,5 @@
+const BigNumber = require('bignumber.js')
+
+const x = new BigNumber('1111222233334444555566')
+
+module.exports = x.toString()
diff --git a/packages/playground/resolve/require-pkg-with-browser-and-module-field/index.cjs b/packages/playground/resolve/require-pkg-with-browser-and-module-field/index.cjs
new file mode 100644
index 00000000000000..86d3360ab38dcb
--- /dev/null
+++ b/packages/playground/resolve/require-pkg-with-browser-and-module-field/index.cjs
@@ -0,0 +1,8 @@
+const dep = require('./dep.cjs')
+
+const msg =
+ dep === '1.111222233334444555566e+21'
+ ? '[success] require-pkg-with-browser-and-module-field'
+ : '[failed] require-pkg-with-browser-and-module-field'
+
+exports.msg = msg
diff --git a/packages/playground/resolve/require-pkg-with-browser-and-module-field/package.json b/packages/playground/resolve/require-pkg-with-browser-and-module-field/package.json
new file mode 100644
index 00000000000000..2a0419b331c407
--- /dev/null
+++ b/packages/playground/resolve/require-pkg-with-browser-and-module-field/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "require-pkg-with-browser-and-module-field",
+ "private": true,
+ "version": "1.0.0",
+ "main": "./index.cjs",
+ "dependencies": {
+ "bignumber.js": "9.0.2"
+ }
+}
diff --git a/packages/playground/resolve/require-pkg-with-esm-entries/index.cjs b/packages/playground/resolve/require-pkg-with-esm-entries/index.cjs
new file mode 100644
index 00000000000000..55958fbdba26ee
--- /dev/null
+++ b/packages/playground/resolve/require-pkg-with-esm-entries/index.cjs
@@ -0,0 +1,9 @@
+const fromEvent = require('callbag-from-event')
+
+const msg =
+ // should be the exported function instead of the ES Module record (`{ default: ... }`)
+ typeof fromEvent === 'function'
+ ? '[success] require-pkg-with-esm-entries'
+ : '[failed] require-pkg-with-esm-entries'
+
+exports.msg = msg
diff --git a/packages/playground/resolve/require-pkg-with-esm-entries/package.json b/packages/playground/resolve/require-pkg-with-esm-entries/package.json
new file mode 100644
index 00000000000000..b845364bb6f19a
--- /dev/null
+++ b/packages/playground/resolve/require-pkg-with-esm-entries/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "require-pkg-with-esm-entries",
+ "private": true,
+ "version": "1.0.0",
+ "main": "./index.cjs",
+ "dependencies": {
+ "callbag-from-event": "1.3.0"
+ }
+}
diff --git a/packages/playground/resolve/vite.config.js b/packages/playground/resolve/vite.config.js
index be1b75e431383a..c1282f4ffc789d 100644
--- a/packages/playground/resolve/vite.config.js
+++ b/packages/playground/resolve/vite.config.js
@@ -40,5 +40,11 @@ module.exports = {
}
}
}
- ]
+ ],
+ optimizeDeps: {
+ include: [
+ 'require-pkg-with-browser-and-module-field',
+ 'require-pkg-with-esm-entries'
+ ]
+ }
}
diff --git a/packages/playground/ssr-deps/__tests__/serve.js b/packages/playground/ssr-deps/__tests__/serve.js
index 5ba5724f2b7a94..6c2584601c9331 100644
--- a/packages/playground/ssr-deps/__tests__/serve.js
+++ b/packages/playground/ssr-deps/__tests__/serve.js
@@ -3,8 +3,9 @@
// the default e2e test serve behavior
const path = require('path')
+const { ports } = require('../../testUtils')
-const port = (exports.port = 9530)
+const port = (exports.port = ports['ssr-deps'])
/**
* @param {string} root
diff --git a/packages/playground/ssr-html/__tests__/serve.js b/packages/playground/ssr-html/__tests__/serve.js
index 5ba5724f2b7a94..d119397700cf75 100644
--- a/packages/playground/ssr-html/__tests__/serve.js
+++ b/packages/playground/ssr-html/__tests__/serve.js
@@ -3,8 +3,9 @@
// the default e2e test serve behavior
const path = require('path')
+const { ports } = require('../../testUtils')
-const port = (exports.port = 9530)
+const port = (exports.port = ports['ssr-html'])
/**
* @param {string} root
diff --git a/packages/playground/ssr-pug/__tests__/serve.js b/packages/playground/ssr-pug/__tests__/serve.js
index 5ba5724f2b7a94..392aa831ebb82d 100644
--- a/packages/playground/ssr-pug/__tests__/serve.js
+++ b/packages/playground/ssr-pug/__tests__/serve.js
@@ -3,8 +3,9 @@
// the default e2e test serve behavior
const path = require('path')
+const { ports } = require('../../testUtils')
-const port = (exports.port = 9530)
+const port = (exports.port = ports['ssr-pug'])
/**
* @param {string} root
diff --git a/packages/playground/ssr-react/__tests__/serve.js b/packages/playground/ssr-react/__tests__/serve.js
index 1bc028c03dc27c..07476e0726e268 100644
--- a/packages/playground/ssr-react/__tests__/serve.js
+++ b/packages/playground/ssr-react/__tests__/serve.js
@@ -3,8 +3,9 @@
// the default e2e test serve behavior
const path = require('path')
+const { ports } = require('../../testUtils')
-const port = (exports.port = 9528)
+const port = (exports.port = ports['ssr-react'])
/**
* @param {string} root
diff --git a/packages/playground/ssr-vue/__tests__/serve.js b/packages/playground/ssr-vue/__tests__/serve.js
index 1e220fed9630e4..5bcd5a4639877a 100644
--- a/packages/playground/ssr-vue/__tests__/serve.js
+++ b/packages/playground/ssr-vue/__tests__/serve.js
@@ -3,8 +3,9 @@
// the default e2e test serve behavior
const path = require('path')
+const { ports } = require('../../testUtils')
-const port = (exports.port = 9527)
+const port = (exports.port = ports['ssr-vue'])
/**
* @param {string} root
diff --git a/packages/playground/ssr-webworker/__tests__/serve.js b/packages/playground/ssr-webworker/__tests__/serve.js
index f4f207b85026c6..38a957b0a333ea 100644
--- a/packages/playground/ssr-webworker/__tests__/serve.js
+++ b/packages/playground/ssr-webworker/__tests__/serve.js
@@ -3,8 +3,9 @@
// the default e2e test serve behavior
const path = require('path')
+const { ports } = require('../../testUtils')
-const port = (exports.port = 9528)
+const port = (exports.port = ports['ssr-webworker'])
/**
* @param {string} root
diff --git a/packages/playground/tailwind-sourcemap/__tests__/build.spec.ts b/packages/playground/tailwind-sourcemap/__tests__/build.spec.ts
new file mode 100644
index 00000000000000..e36c1f52d2c1f8
--- /dev/null
+++ b/packages/playground/tailwind-sourcemap/__tests__/build.spec.ts
@@ -0,0 +1,13 @@
+import { isBuild } from 'testUtils'
+
+if (isBuild) {
+ test('should not output sourcemap warning (#4939)', () => {
+ serverLogs.forEach((log) => {
+ expect(log).not.toMatch('Sourcemap is likely to be incorrect')
+ })
+ })
+} else {
+ test('this file only includes test for build', () => {
+ expect(true).toBe(true)
+ })
+}
diff --git a/packages/playground/tailwind-sourcemap/__tests__/serve.spec.ts b/packages/playground/tailwind-sourcemap/__tests__/serve.spec.ts
new file mode 100644
index 00000000000000..d961f75e4536e5
--- /dev/null
+++ b/packages/playground/tailwind-sourcemap/__tests__/serve.spec.ts
@@ -0,0 +1,13 @@
+import { isBuild } from 'testUtils'
+
+if (!isBuild) {
+ test('should not output missing source file warning', () => {
+ serverLogs.forEach((log) => {
+ expect(log).not.toMatch(/Sourcemap for .+ points to missing source files/)
+ })
+ })
+} else {
+ test('this file only includes test for serve', () => {
+ expect(true).toBe(true)
+ })
+}
diff --git a/packages/playground/tailwind-sourcemap/index.html b/packages/playground/tailwind-sourcemap/index.html
new file mode 100644
index 00000000000000..95c8c5da7716d1
--- /dev/null
+++ b/packages/playground/tailwind-sourcemap/index.html
@@ -0,0 +1,9 @@
+
+
Tailwind Sourcemap
+
+
foo
+
+
+
diff --git a/packages/playground/tailwind-sourcemap/package.json b/packages/playground/tailwind-sourcemap/package.json
new file mode 100644
index 00000000000000..5c374f3bf47f1b
--- /dev/null
+++ b/packages/playground/tailwind-sourcemap/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "test-tailwind-sourcemap",
+ "private": true,
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "debug": "node --inspect-brk ../../vite/bin/vite",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "tailwindcss": "^3.0.23"
+ }
+}
diff --git a/packages/playground/tailwind-sourcemap/postcss.config.js b/packages/playground/tailwind-sourcemap/postcss.config.js
new file mode 100644
index 00000000000000..eab3760cbc7b42
--- /dev/null
+++ b/packages/playground/tailwind-sourcemap/postcss.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ plugins: {
+ tailwindcss: { config: __dirname + '/tailwind.config.js' }
+ }
+}
diff --git a/packages/playground/tailwind-sourcemap/tailwind.config.js b/packages/playground/tailwind-sourcemap/tailwind.config.js
new file mode 100644
index 00000000000000..f89a536ccd742f
--- /dev/null
+++ b/packages/playground/tailwind-sourcemap/tailwind.config.js
@@ -0,0 +1,7 @@
+module.exports = {
+ content: ['./index.html'],
+ theme: {
+ extend: {}
+ },
+ plugins: []
+}
diff --git a/packages/playground/tailwind-sourcemap/tailwind.css b/packages/playground/tailwind-sourcemap/tailwind.css
new file mode 100644
index 00000000000000..b5c61c956711f9
--- /dev/null
+++ b/packages/playground/tailwind-sourcemap/tailwind.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/packages/playground/tailwind-sourcemap/vite.config.js b/packages/playground/tailwind-sourcemap/vite.config.js
new file mode 100644
index 00000000000000..70fea77247bcd4
--- /dev/null
+++ b/packages/playground/tailwind-sourcemap/vite.config.js
@@ -0,0 +1,11 @@
+/**
+ * @type {import('vite').UserConfig}
+ */
+module.exports = {
+ css: {
+ devSourcemap: true
+ },
+ build: {
+ sourcemap: true
+ }
+}
diff --git a/packages/playground/testUtils.ts b/packages/playground/testUtils.ts
index 0c8186d4ed121d..427fea6d947a4f 100644
--- a/packages/playground/testUtils.ts
+++ b/packages/playground/testUtils.ts
@@ -7,6 +7,25 @@ import path from 'path'
import colors from 'css-color-names'
import type { ElementHandle } from 'playwright-chromium'
import type { Manifest } from 'vite'
+import { normalizePath } from 'vite'
+import { fromComment } from 'convert-source-map'
+
+// make sure these ports are unique
+export const ports = {
+ cli: 9510,
+ 'cli-module': 9511,
+ 'legacy/ssr': 9520,
+ lib: 9521,
+ 'optimize-missing-deps': 9522,
+ 'ssr-deps': 9600,
+ 'ssr-html': 9601,
+ 'ssr-pug': 9602,
+ 'ssr-react': 9603,
+ 'ssr-vue': 9604,
+ 'ssr-webworker': 9605,
+ 'css/postcss-caching': 5005,
+ 'css/postcss-plugins-different-dir': 5006
+}
export function slash(p: string): string {
return p.replace(/\\/g, '/')
@@ -138,3 +157,17 @@ export async function untilUpdated(
* Send the rebuild complete message in build watch
*/
export { notifyRebuildComplete } from '../../scripts/jestPerTestSetup'
+
+export const extractSourcemap = (content: string) => {
+ const lines = content.trim().split('\n')
+ return fromComment(lines[lines.length - 1]).toObject()
+}
+
+export const formatSourcemapForSnapshot = (map: any) => {
+ const root = normalizePath(testDir)
+ const m = { ...map }
+ delete m.file
+ delete m.names
+ m.sources = m.sources.map((source) => source.replace(root, '/root'))
+ return m
+}
diff --git a/packages/playground/vue-sourcemap/Js.vue b/packages/playground/vue-sourcemap/Js.vue
new file mode 100644
index 00000000000000..3a5577099f67d3
--- /dev/null
+++ b/packages/playground/vue-sourcemap/Js.vue
@@ -0,0 +1,11 @@
+
+ <js>
+
+
+
+
+
diff --git a/packages/playground/vue-sourcemap/Main.vue b/packages/playground/vue-sourcemap/Main.vue
index 04ddf50071ccb3..b9b03596f5aea5 100644
--- a/packages/playground/vue-sourcemap/Main.vue
+++ b/packages/playground/vue-sourcemap/Main.vue
@@ -1,5 +1,7 @@
Vue SFC Sourcemap
+
+
@@ -8,6 +10,8 @@
+
+
diff --git a/packages/playground/vue-sourcemap/__tests__/serve.spec.ts b/packages/playground/vue-sourcemap/__tests__/serve.spec.ts
index 193b0afb9ba73f..08b4c04face111 100644
--- a/packages/playground/vue-sourcemap/__tests__/serve.spec.ts
+++ b/packages/playground/vue-sourcemap/__tests__/serve.spec.ts
@@ -1,10 +1,11 @@
-import { fromComment } from 'convert-source-map'
-import { normalizePath } from 'vite'
-import { isBuild, testDir } from 'testUtils'
+import {
+ extractSourcemap,
+ formatSourcemapForSnapshot,
+ isBuild
+} from 'testUtils'
+import { URL } from 'url'
if (!isBuild) {
- const root = normalizePath(testDir)
-
const getStyleTagContentIncluding = async (content: string) => {
const styles = await page.$$('style')
for (const style of styles) {
@@ -16,18 +17,63 @@ if (!isBuild) {
throw new Error('Not found')
}
- const extractSourcemap = (content: string) => {
- const lines = content.trim().split('\n')
- return fromComment(lines[lines.length - 1]).toObject()
- }
+ test('js', async () => {
+ const res = await page.request.get(new URL('./Js.vue', page.url()).href)
+ const js = await res.text()
+ const map = extractSourcemap(js)
+ expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(`
+ Object {
+ "mappings": "AAKA,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;;;;AAGP;AACd,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;wBARlB,oBAAiB,WAAd,MAAU",
+ "sources": Array [
+ "/root/Js.vue",
+ ],
+ "sourcesContent": Array [
+ "
+ <js>
+
- const formatSourcemapForSnapshot = (map: any) => {
- const m = { ...map }
- delete m.file
- delete m.names
- m.sources = m.sources.map((source) => source.replace(root, '/root'))
- return m
- }
+
+
+
+ ",
+ ],
+ "version": 3,
+ }
+ `)
+ })
+
+ test('ts', async () => {
+ const res = await page.request.get(new URL('./Ts.vue', page.url()).href)
+ const js = await res.text()
+ const map = extractSourcemap(js)
+ expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(`
+ Object {
+ "mappings": ";AAKA,QAAQ,IAAI,WAAW;;;;AAIvB,YAAQ,IAAI,UAAU;;;;;;;;uBARpB,oBAAiB,WAAd,MAAU",
+ "sources": Array [
+ "/root/Ts.vue",
+ ],
+ "sourcesContent": Array [
+ "
+ <ts>
+
+
+
+
+
+ ",
+ ],
+ "version": 3,
+ }
+ `)
+ })
test('css', async () => {
const css = await getStyleTagContentIncluding('.css ')
diff --git a/packages/playground/vue-sourcemap/package.json b/packages/playground/vue-sourcemap/package.json
index 5672b5e3d9d57d..286940b01efa58 100644
--- a/packages/playground/vue-sourcemap/package.json
+++ b/packages/playground/vue-sourcemap/package.json
@@ -10,7 +10,6 @@
},
"devDependencies": {
"@vitejs/plugin-vue": "workspace:*",
- "convert-source-map": "^1.8.0",
"less": "^4.1.2",
"sass": "^1.43.4"
},
diff --git a/packages/playground/vue-sourcemap/vite.config.js b/packages/playground/vue-sourcemap/vite.config.js
index 045410259fe590..2a48cad3cb00d4 100644
--- a/packages/playground/vue-sourcemap/vite.config.js
+++ b/packages/playground/vue-sourcemap/vite.config.js
@@ -5,6 +5,7 @@ const vuePlugin = require('@vitejs/plugin-vue')
*/
module.exports = {
css: {
+ devSourcemap: true,
preprocessorOptions: {
less: {
additionalData: '@color: red;'
diff --git a/packages/playground/vue/Main.vue b/packages/playground/vue/Main.vue
index d10ae401f7aa8e..87319acdf6f736 100644
--- a/packages/playground/vue/Main.vue
+++ b/packages/playground/vue/Main.vue
@@ -20,6 +20,7 @@
+
diff --git a/packages/playground/vue/workerTest.js b/packages/playground/vue/workerTest.js
new file mode 100644
index 00000000000000..fcde5e19b30677
--- /dev/null
+++ b/packages/playground/vue/workerTest.js
@@ -0,0 +1 @@
+self.postMessage('worker load!')
diff --git a/packages/playground/worker/__tests__/es/es-worker.spec.ts b/packages/playground/worker/__tests__/es/es-worker.spec.ts
new file mode 100644
index 00000000000000..c7fd0d6c19e4bc
--- /dev/null
+++ b/packages/playground/worker/__tests__/es/es-worker.spec.ts
@@ -0,0 +1,102 @@
+import fs from 'fs'
+import path from 'path'
+import { untilUpdated, isBuild, testDir } from '../../../testUtils'
+import type { Page } from 'playwright-chromium'
+
+test('normal', async () => {
+ await page.click('.ping')
+ await untilUpdated(() => page.textContent('.pong'), 'pong')
+ await untilUpdated(
+ () => page.textContent('.mode'),
+ isBuild ? 'production' : 'development'
+ )
+ await untilUpdated(
+ () => page.textContent('.bundle-with-plugin'),
+ 'worker bundle with plugin success!'
+ )
+})
+
+test('TS output', async () => {
+ await page.click('.ping-ts-output')
+ await untilUpdated(() => page.textContent('.pong-ts-output'), 'pong')
+})
+
+test('inlined', async () => {
+ await page.click('.ping-inline')
+ await untilUpdated(() => page.textContent('.pong-inline'), 'pong')
+})
+
+const waitSharedWorkerTick = (
+ (resolvedSharedWorkerCount: number) => async (page: Page) => {
+ await untilUpdated(async () => {
+ const count = await page.textContent('.tick-count')
+ // ignore the initial 0
+ return count === '1' ? 'page loaded' : ''
+ }, 'page loaded')
+ // test.concurrent sequential is not guaranteed
+ // force page to wait to ensure two pages overlap in time
+ resolvedSharedWorkerCount++
+ if (resolvedSharedWorkerCount < 2) return
+
+ await untilUpdated(() => {
+ return resolvedSharedWorkerCount === 2 ? 'all pages loaded' : ''
+ }, 'all pages loaded')
+ }
+)(0)
+
+test.concurrent.each([[true], [false]])('shared worker', async (doTick) => {
+ if (doTick) {
+ await page.click('.tick-shared')
+ }
+ await waitSharedWorkerTick(page)
+})
+
+test('worker emitted', async () => {
+ await untilUpdated(() => page.textContent('.nested-worker'), 'pong')
+})
+
+if (isBuild) {
+ const assetsDir = path.resolve(testDir, 'dist/es/assets')
+ // assert correct files
+ test('inlined code generation', async () => {
+ const files = fs.readdirSync(assetsDir)
+ expect(files.length).toBe(22)
+ const index = files.find((f) => f.includes('main-module'))
+ const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
+ const worker = files.find((f) => f.includes('my-worker'))
+ const workerContent = fs.readFileSync(
+ path.resolve(assetsDir, worker),
+ 'utf-8'
+ )
+
+ // worker should have all imports resolved and no exports
+ expect(workerContent).not.toMatch(`import`)
+ expect(workerContent).not.toMatch(`export`)
+ // chunk
+ expect(content).toMatch(`new Worker("/es/assets`)
+ expect(content).toMatch(`new SharedWorker("/es/assets`)
+ // inlined
+ expect(content).toMatch(`(window.URL||window.webkitURL).createObjectURL`)
+ expect(content).toMatch(`window.Blob`)
+ })
+}
+
+test('module worker', async () => {
+ expect(await page.textContent('.shared-worker-import-meta-url')).toMatch(
+ 'A string'
+ )
+})
+
+test('classic worker', async () => {
+ expect(await page.textContent('.classic-worker')).toMatch('A classic')
+ expect(await page.textContent('.classic-shared-worker')).toMatch('A classic')
+})
+
+test('emit chunk', async () => {
+ expect(await page.textContent('.emti-chunk-worker')).toMatch(
+ '["A string",{"type":"emit-chunk-sub-worker","data":"A string"},{"type":"module-and-worker:worker","data":"A string"},{"type":"module-and-worker:module","data":"module and worker"},{"type":"emit-chunk-sub-worker","data":{"module":"module and worker","msg1":"module1","msg2":"module2","msg3":"module3"}}]'
+ )
+ expect(await page.textContent('.emti-chunk-dynamic-import-worker')).toMatch(
+ '"A string/es/"'
+ )
+})
diff --git a/packages/playground/worker/__tests__/es/vite.config.js b/packages/playground/worker/__tests__/es/vite.config.js
new file mode 100644
index 00000000000000..931d457792c4f9
--- /dev/null
+++ b/packages/playground/worker/__tests__/es/vite.config.js
@@ -0,0 +1 @@
+module.exports = require('../../vite.config-es')
diff --git a/packages/playground/worker/__tests__/iife/vite.config.js b/packages/playground/worker/__tests__/iife/vite.config.js
new file mode 100644
index 00000000000000..4204f532b7ac1c
--- /dev/null
+++ b/packages/playground/worker/__tests__/iife/vite.config.js
@@ -0,0 +1 @@
+module.exports = require('../../vite.config')
diff --git a/packages/playground/worker/__tests__/worker.spec.ts b/packages/playground/worker/__tests__/iife/worker.spec.ts
similarity index 77%
rename from packages/playground/worker/__tests__/worker.spec.ts
rename to packages/playground/worker/__tests__/iife/worker.spec.ts
index 6d93e810c0c510..fa9f72fe76131c 100644
--- a/packages/playground/worker/__tests__/worker.spec.ts
+++ b/packages/playground/worker/__tests__/iife/worker.spec.ts
@@ -1,6 +1,6 @@
import fs from 'fs'
import path from 'path'
-import { untilUpdated, isBuild, testDir } from '../../testUtils'
+import { untilUpdated, isBuild, testDir } from '../../../testUtils'
import type { Page } from 'playwright-chromium'
test('normal', async () => {
@@ -51,21 +51,20 @@ test.concurrent.each([[true], [false]])('shared worker', async (doTick) => {
await waitSharedWorkerTick(page)
})
-test('worker emitted', async () => {
- await untilUpdated(() => page.textContent('.nested-worker'), 'pong')
+test('worker emitted and import.meta.url in nested worker', async () => {
await untilUpdated(
- () => page.textContent('.nested-worker-dynamic-import'),
- '"msg":"pong"'
+ () => page.textContent('.nested-worker'),
+ 'pong http://localhost:3000/iife/sub-worker.js?worker_file'
)
})
if (isBuild) {
- const assetsDir = path.resolve(testDir, 'dist/assets')
+ const assetsDir = path.resolve(testDir, 'dist/iife/assets')
// assert correct files
test('inlined code generation', async () => {
const files = fs.readdirSync(assetsDir)
- expect(files.length).toBe(11)
- const index = files.find((f) => f.includes('index'))
+ expect(files.length).toBe(13)
+ const index = files.find((f) => f.includes('main-module'))
const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
const worker = files.find((f) => f.includes('my-worker'))
const workerContent = fs.readFileSync(
@@ -77,15 +76,21 @@ if (isBuild) {
expect(workerContent).not.toMatch(`import`)
expect(workerContent).not.toMatch(`export`)
// chunk
- expect(content).toMatch(`new Worker("/assets`)
- expect(content).toMatch(`new SharedWorker("/assets`)
+ expect(content).toMatch(`new Worker("/iife/assets`)
+ expect(content).toMatch(`new SharedWorker("/iife/assets`)
// inlined
expect(content).toMatch(`(window.URL||window.webkitURL).createObjectURL`)
expect(content).toMatch(`window.Blob`)
})
}
-test('classic worker is run', async () => {
+test('module worker', async () => {
+ expect(await page.textContent('.shared-worker-import-meta-url')).toMatch(
+ 'A string'
+ )
+})
+
+test('classic worker', async () => {
expect(await page.textContent('.classic-worker')).toMatch('A classic')
expect(await page.textContent('.classic-shared-worker')).toMatch('A classic')
})
diff --git a/packages/playground/worker/__tests__/sourcemap-hidden/sourcemap-hidden-worker.spec.ts b/packages/playground/worker/__tests__/sourcemap-hidden/sourcemap-hidden-worker.spec.ts
new file mode 100644
index 00000000000000..d846a5de2311d0
--- /dev/null
+++ b/packages/playground/worker/__tests__/sourcemap-hidden/sourcemap-hidden-worker.spec.ts
@@ -0,0 +1,129 @@
+import fs from 'fs'
+import path from 'path'
+import { untilUpdated, isBuild, testDir } from '../../../testUtils'
+import { Page } from 'playwright-chromium'
+
+if (isBuild) {
+ const assetsDir = path.resolve(testDir, 'dist/iife-sourcemap-hidden/assets')
+ // assert correct files
+ test('sourcemap generation for web workers', async () => {
+ const files = fs.readdirSync(assetsDir)
+ // should have 2 worker chunk
+ expect(files.length).toBe(25)
+ const index = files.find((f) => f.includes('main-module'))
+ const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
+ const indexSourcemap = getSourceMapUrl(content)
+ const worker = files.find((f) => /^my-worker\.\w+\.js$/.test(f))
+ const workerContent = fs.readFileSync(
+ path.resolve(assetsDir, worker),
+ 'utf-8'
+ )
+ const workerSourcemap = getSourceMapUrl(workerContent)
+ const sharedWorker = files.find((f) =>
+ /^my-shared-worker\.\w+\.js$/.test(f)
+ )
+ const sharedWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, sharedWorker),
+ 'utf-8'
+ )
+ const sharedWorkerSourcemap = getSourceMapUrl(sharedWorkerContent)
+ const possibleTsOutputWorker = files.find((f) =>
+ /^possible-ts-output-worker\.\w+\.js$/.test(f)
+ )
+ const possibleTsOutputWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, possibleTsOutputWorker),
+ 'utf-8'
+ )
+ const possibleTsOutputWorkerSourcemap = getSourceMapUrl(
+ possibleTsOutputWorkerContent
+ )
+ const workerNestedWorker = files.find((f) =>
+ /^worker-nested-worker\.\w+\.js$/.test(f)
+ )
+ const workerNestedWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, workerNestedWorker),
+ 'utf-8'
+ )
+ const workerNestedWorkerSourcemap = getSourceMapUrl(
+ workerNestedWorkerContent
+ )
+ const subWorker = files.find((f) => /^sub-worker\.\w+\.js$/.test(f))
+ const subWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, subWorker),
+ 'utf-8'
+ )
+ const subWorkerSourcemap = getSourceMapUrl(subWorkerContent)
+
+ expect(files).toContainEqual(expect.stringMatching(/^index\.\w+\.js\.map$/))
+ expect(files).toContainEqual(
+ expect.stringMatching(/^my-worker\.\w+\.js\.map$/)
+ )
+ expect(files).toContainEqual(
+ expect.stringMatching(/^my-shared-worker\.\w+\.js\.map$/)
+ )
+ expect(files).toContainEqual(
+ expect.stringMatching(/^possible-ts-output-worker\.\w+\.js\.map$/)
+ )
+ expect(files).toContainEqual(
+ expect.stringMatching(/^worker-nested-worker\.\w+\.js\.map$/)
+ )
+ expect(files).toContainEqual(
+ expect.stringMatching(/^sub-worker\.\w+\.js\.map$/)
+ )
+
+ // sourcemap should exist and have a data URL
+ expect(indexSourcemap).toBe(null)
+ expect(workerSourcemap).toBe(null)
+ expect(sharedWorkerSourcemap).toBe(null)
+ expect(possibleTsOutputWorkerSourcemap).toBe(null)
+ expect(workerNestedWorkerSourcemap).toBe(null)
+ expect(subWorkerSourcemap).toBe(null)
+
+ // worker should have all imports resolved and no exports
+ expect(workerContent).not.toMatch(`import`)
+ expect(workerContent).not.toMatch(`export`)
+
+ // shared worker should have all imports resolved and no exports
+ expect(sharedWorkerContent).not.toMatch(`import`)
+ expect(sharedWorkerContent).not.toMatch(`export`)
+
+ // chunk
+ expect(content).toMatch(
+ `new Worker("/iife-sourcemap-hidden/assets/my-worker`
+ )
+ expect(content).toMatch(`new Worker("data:application/javascript;base64`)
+ expect(content).toMatch(
+ `new Worker("/iife-sourcemap-hidden/assets/possible-ts-output-worker`
+ )
+ expect(content).toMatch(
+ `new Worker("/iife-sourcemap-hidden/assets/worker-nested-worker`
+ )
+ expect(content).toMatch(
+ `new SharedWorker("/iife-sourcemap-hidden/assets/my-shared-worker`
+ )
+
+ // inlined
+ expect(content).toMatch(`(window.URL||window.webkitURL).createObjectURL`)
+ expect(content).toMatch(`window.Blob`)
+
+ expect(workerNestedWorkerContent).toMatch(
+ `new Worker("/iife-sourcemap-hidden/assets/sub-worker`
+ )
+ })
+} else {
+ // Workaround so that testing serve does not emit
+ // "Your test suite must contain at least one test"
+ test('true', () => {
+ expect(true).toBe(true)
+ })
+}
+
+function getSourceMapUrl(code: string): string {
+ const regex = /\/\/[#@]\s(?:source(?:Mapping)?URL)=\s*(\S+)/g
+ const results = regex.exec(code)
+
+ if (results && results.length >= 2) {
+ return results[1]
+ }
+ return null
+}
diff --git a/packages/playground/worker/__tests__/sourcemap-hidden/vite.config.js b/packages/playground/worker/__tests__/sourcemap-hidden/vite.config.js
new file mode 100644
index 00000000000000..d51907577e9deb
--- /dev/null
+++ b/packages/playground/worker/__tests__/sourcemap-hidden/vite.config.js
@@ -0,0 +1 @@
+module.exports = require('../../vite.config-sourcemap')('hidden')
diff --git a/packages/playground/worker/__tests__/sourcemap-inline/sourcemap-inline-worker.spec.ts b/packages/playground/worker/__tests__/sourcemap-inline/sourcemap-inline-worker.spec.ts
new file mode 100644
index 00000000000000..ceda7dae1fec7c
--- /dev/null
+++ b/packages/playground/worker/__tests__/sourcemap-inline/sourcemap-inline-worker.spec.ts
@@ -0,0 +1,112 @@
+import fs from 'fs'
+import path from 'path'
+import { untilUpdated, isBuild, testDir } from '../../../testUtils'
+import { Page } from 'playwright-chromium'
+
+if (isBuild) {
+ const assetsDir = path.resolve(testDir, 'dist/iife-sourcemap-inline/assets')
+ // assert correct files
+ test('sourcemap generation for web workers', async () => {
+ const files = fs.readdirSync(assetsDir)
+ // should have 2 worker chunk
+ expect(files.length).toBe(13)
+ const index = files.find((f) => f.includes('main-module'))
+ const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
+ const indexSourcemap = getSourceMapUrl(content)
+ const worker = files.find((f) => /^my-worker\.\w+\.js$/.test(f))
+ const workerContent = fs.readFileSync(
+ path.resolve(assetsDir, worker),
+ 'utf-8'
+ )
+ const workerSourcemap = getSourceMapUrl(workerContent)
+ const sharedWorker = files.find((f) =>
+ /^my-shared-worker\.\w+\.js$/.test(f)
+ )
+ const sharedWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, sharedWorker),
+ 'utf-8'
+ )
+ const sharedWorkerSourcemap = getSourceMapUrl(sharedWorkerContent)
+ const possibleTsOutputWorker = files.find((f) =>
+ /^possible-ts-output-worker\.\w+\.js$/.test(f)
+ )
+ const possibleTsOutputWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, possibleTsOutputWorker),
+ 'utf-8'
+ )
+ const possibleTsOutputWorkerSourcemap = getSourceMapUrl(
+ possibleTsOutputWorkerContent
+ )
+ const workerNestedWorker = files.find((f) =>
+ /^worker-nested-worker\.\w+\.js$/.test(f)
+ )
+ const workerNestedWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, workerNestedWorker),
+ 'utf-8'
+ )
+ const workerNestedWorkerSourcemap = getSourceMapUrl(
+ workerNestedWorkerContent
+ )
+ const subWorker = files.find((f) => /^sub-worker\.\w+\.js$/.test(f))
+ const subWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, subWorker),
+ 'utf-8'
+ )
+ const subWorkerSourcemap = getSourceMapUrl(subWorkerContent)
+
+ // sourcemap should exist and have a data URL
+ expect(indexSourcemap).toMatch(/^data:/)
+ expect(workerSourcemap).toMatch(/^data:/)
+ expect(sharedWorkerSourcemap).toMatch(/^data:/)
+ expect(possibleTsOutputWorkerSourcemap).toMatch(/^data:/)
+ expect(workerNestedWorkerSourcemap).toMatch(/^data:/)
+ expect(subWorkerSourcemap).toMatch(/^data:/)
+
+ // worker should have all imports resolved and no exports
+ expect(workerContent).not.toMatch(`import`)
+ expect(workerContent).not.toMatch(`export`)
+
+ // shared worker should have all imports resolved and no exports
+ expect(sharedWorkerContent).not.toMatch(`import`)
+ expect(sharedWorkerContent).not.toMatch(`export`)
+
+ // chunk
+ expect(content).toMatch(
+ `new Worker("/iife-sourcemap-inline/assets/my-worker`
+ )
+ expect(content).toMatch(`new Worker("data:application/javascript;base64`)
+ expect(content).toMatch(
+ `new Worker("/iife-sourcemap-inline/assets/possible-ts-output-worker`
+ )
+ expect(content).toMatch(
+ `new Worker("/iife-sourcemap-inline/assets/worker-nested-worker`
+ )
+ expect(content).toMatch(
+ `new SharedWorker("/iife-sourcemap-inline/assets/my-shared-worker`
+ )
+
+ // inlined
+ expect(content).toMatch(`(window.URL||window.webkitURL).createObjectURL`)
+ expect(content).toMatch(`window.Blob`)
+
+ expect(workerNestedWorkerContent).toMatch(
+ `new Worker("/iife-sourcemap-inline/assets/sub-worker`
+ )
+ })
+} else {
+ // Workaround so that testing serve does not emit
+ // "Your test suite must contain at least one test"
+ test('true', () => {
+ expect(true).toBe(true)
+ })
+}
+
+function getSourceMapUrl(code: string): string {
+ const regex = /\/\/[#@]\s(?:source(?:Mapping)?URL)=\s*(\S+)/g
+ const results = regex.exec(code)
+
+ if (results && results.length >= 2) {
+ return results[1]
+ }
+ return null
+}
diff --git a/packages/playground/worker/__tests__/sourcemap-inline/vite.config.js b/packages/playground/worker/__tests__/sourcemap-inline/vite.config.js
new file mode 100644
index 00000000000000..abe37cd56accd6
--- /dev/null
+++ b/packages/playground/worker/__tests__/sourcemap-inline/vite.config.js
@@ -0,0 +1 @@
+module.exports = require('../../vite.config-sourcemap')('inline')
diff --git a/packages/playground/worker/__tests__/sourcemap/sourcemap-worker.spec.ts b/packages/playground/worker/__tests__/sourcemap/sourcemap-worker.spec.ts
new file mode 100644
index 00000000000000..54e4f1cb9f2d58
--- /dev/null
+++ b/packages/playground/worker/__tests__/sourcemap/sourcemap-worker.spec.ts
@@ -0,0 +1,131 @@
+import fs from 'fs'
+import path from 'path'
+import { untilUpdated, isBuild, testDir } from '../../../testUtils'
+import { Page } from 'playwright-chromium'
+
+if (isBuild) {
+ const assetsDir = path.resolve(testDir, 'dist/iife-sourcemap/assets')
+ // assert correct files
+ test('sourcemap generation for web workers', async () => {
+ const files = fs.readdirSync(assetsDir)
+ // should have 2 worker chunk
+ expect(files.length).toBe(25)
+ const index = files.find((f) => f.includes('main-module'))
+ const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
+ const indexSourcemap = getSourceMapUrl(content)
+ const worker = files.find((f) => /^my-worker\.\w+\.js$/.test(f))
+ const workerContent = fs.readFileSync(
+ path.resolve(assetsDir, worker),
+ 'utf-8'
+ )
+ const workerSourcemap = getSourceMapUrl(workerContent)
+ const sharedWorker = files.find((f) =>
+ /^my-shared-worker\.\w+\.js$/.test(f)
+ )
+ const sharedWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, sharedWorker),
+ 'utf-8'
+ )
+ const sharedWorkerSourcemap = getSourceMapUrl(sharedWorkerContent)
+ const possibleTsOutputWorker = files.find((f) =>
+ /^possible-ts-output-worker\.\w+\.js$/.test(f)
+ )
+ const possibleTsOutputWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, possibleTsOutputWorker),
+ 'utf-8'
+ )
+ const possibleTsOutputWorkerSourcemap = getSourceMapUrl(
+ possibleTsOutputWorkerContent
+ )
+ const workerNestedWorker = files.find((f) =>
+ /^worker-nested-worker\.\w+\.js$/.test(f)
+ )
+ const workerNestedWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, workerNestedWorker),
+ 'utf-8'
+ )
+ const workerNestedWorkerSourcemap = getSourceMapUrl(
+ workerNestedWorkerContent
+ )
+ const subWorker = files.find((f) => /^sub-worker\.\w+\.js$/.test(f))
+ const subWorkerContent = fs.readFileSync(
+ path.resolve(assetsDir, subWorker),
+ 'utf-8'
+ )
+ const subWorkerSourcemap = getSourceMapUrl(subWorkerContent)
+
+ expect(files).toContainEqual(expect.stringMatching(/^index\.\w+\.js\.map$/))
+ expect(files).toContainEqual(
+ expect.stringMatching(/^my-worker\.\w+\.js\.map$/)
+ )
+ expect(files).toContainEqual(
+ expect.stringMatching(/^my-shared-worker\.\w+\.js\.map$/)
+ )
+ expect(files).toContainEqual(
+ expect.stringMatching(/^possible-ts-output-worker\.\w+\.js\.map$/)
+ )
+ expect(files).toContainEqual(
+ expect.stringMatching(/^worker-nested-worker\.\w+\.js\.map$/)
+ )
+ expect(files).toContainEqual(
+ expect.stringMatching(/^sub-worker\.\w+\.js\.map$/)
+ )
+
+ // sourcemap should exist and have a data URL
+ expect(indexSourcemap).toMatch(/^main-module\.\w+\.js\.map$/)
+ expect(workerSourcemap).toMatch(/^my-worker\.\w+\.js\.map$/)
+ expect(sharedWorkerSourcemap).toMatch(/^my-shared-worker\.\w+\.js\.map$/)
+ expect(possibleTsOutputWorkerSourcemap).toMatch(
+ /^possible-ts-output-worker\.\w+\.js\.map$/
+ )
+ expect(workerNestedWorkerSourcemap).toMatch(
+ /^worker-nested-worker\.\w+\.js\.map$/
+ )
+ expect(subWorkerSourcemap).toMatch(/^sub-worker\.\w+\.js\.map$/)
+
+ // worker should have all imports resolved and no exports
+ expect(workerContent).not.toMatch(`import`)
+ expect(workerContent).not.toMatch(`export`)
+
+ // shared worker should have all imports resolved and no exports
+ expect(sharedWorkerContent).not.toMatch(`import`)
+ expect(sharedWorkerContent).not.toMatch(`export`)
+
+ // chunk
+ expect(content).toMatch(`new Worker("/iife-sourcemap/assets/my-worker`)
+ expect(content).toMatch(`new Worker("data:application/javascript;base64`)
+ expect(content).toMatch(
+ `new Worker("/iife-sourcemap/assets/possible-ts-output-worker`
+ )
+ expect(content).toMatch(
+ `new Worker("/iife-sourcemap/assets/worker-nested-worker`
+ )
+ expect(content).toMatch(
+ `new SharedWorker("/iife-sourcemap/assets/my-shared-worker`
+ )
+
+ // inlined
+ expect(content).toMatch(`(window.URL||window.webkitURL).createObjectURL`)
+ expect(content).toMatch(`window.Blob`)
+
+ expect(workerNestedWorkerContent).toMatch(
+ `new Worker("/iife-sourcemap/assets/sub-worker`
+ )
+ })
+} else {
+ // Workaround so that testing serve does not emit
+ // "Your test suite must contain at least one test"
+ test('true', () => {
+ expect(true).toBe(true)
+ })
+}
+
+function getSourceMapUrl(code: string): string {
+ const regex = /\/\/[#@]\s(?:source(?:Mapping)?URL)=\s*(\S+)/g
+ const results = regex.exec(code)
+
+ if (results && results.length >= 2) {
+ return results[1]
+ }
+ return null
+}
diff --git a/packages/playground/worker/__tests__/sourcemap/vite.config.js b/packages/playground/worker/__tests__/sourcemap/vite.config.js
new file mode 100644
index 00000000000000..7d3aeeeb774e18
--- /dev/null
+++ b/packages/playground/worker/__tests__/sourcemap/vite.config.js
@@ -0,0 +1 @@
+module.exports = require('../../vite.config-sourcemap')(true)
diff --git a/packages/playground/worker/newUrl/classic-shared-worker.js b/packages/playground/worker/classic-shared-worker.js
similarity index 58%
rename from packages/playground/worker/newUrl/classic-shared-worker.js
rename to packages/playground/worker/classic-shared-worker.js
index 462e49dfa8847f..8bd39e194f0618 100644
--- a/packages/playground/worker/newUrl/classic-shared-worker.js
+++ b/packages/playground/worker/classic-shared-worker.js
@@ -1,4 +1,4 @@
-importScripts('/classic.js')
+importScripts(`/${self.location.pathname.split('/')[1]}/classic.js`)
self.onconnect = (event) => {
const port = event.ports[0]
diff --git a/packages/playground/worker/classic-worker.js b/packages/playground/worker/classic-worker.js
index bb6f9c3f49fc84..0700428ee0c80b 100644
--- a/packages/playground/worker/classic-worker.js
+++ b/packages/playground/worker/classic-worker.js
@@ -1,29 +1,5 @@
-// prettier-ignore
-function text(el, text) {
- document.querySelector(el).textContent = text
-}
+importScripts(`/${self.location.pathname.split("/")[1]}/classic.js`)
-const classicWorker = new Worker(
- new URL('./newUrl/classic-worker.js', import.meta.url) /* , */ ,
- // test comment
-
-)
-
-classicWorker.addEventListener('message', ({ data }) => {
- text('.classic-worker', data)
-})
-classicWorker.postMessage('ping')
-
-const classicSharedWorker = new SharedWorker(
- new URL('./newUrl/classic-shared-worker.js', import.meta.url),
- {
- type: 'classic'
- }
-)
-classicSharedWorker.port.addEventListener('message', (ev) => {
- text(
- '.classic-shared-worker',
- ev.data
- )
+self.addEventListener('message', () => {
+ self.postMessage(self.constant)
})
-classicSharedWorker.port.start()
diff --git a/packages/playground/worker/emit-chunk-dynamic-import-worker.js b/packages/playground/worker/emit-chunk-dynamic-import-worker.js
new file mode 100644
index 00000000000000..f96e0b15d26497
--- /dev/null
+++ b/packages/playground/worker/emit-chunk-dynamic-import-worker.js
@@ -0,0 +1,3 @@
+import('./modules/module').then((module) => {
+ self.postMessage(module.default + import.meta.env.BASE_URL)
+})
diff --git a/packages/playground/worker/emit-chunk-nested-worker.js b/packages/playground/worker/emit-chunk-nested-worker.js
new file mode 100644
index 00000000000000..6cb72b9488cfaf
--- /dev/null
+++ b/packages/playground/worker/emit-chunk-nested-worker.js
@@ -0,0 +1,28 @@
+import SubWorker from './emit-chunk-sub-worker?worker'
+const subWorker = new SubWorker()
+
+subWorker.onmessage = (event) => {
+ self.postMessage({
+ type: 'emit-chunk-sub-worker',
+ data: event.data
+ })
+}
+
+const moduleWorker = new Worker(
+ new URL('./module-and-worker.js', import.meta.url),
+ { type: 'module' }
+)
+
+moduleWorker.onmessage = (event) => {
+ self.postMessage({
+ type: 'module-and-worker:worker',
+ data: event.data
+ })
+}
+
+import('./module-and-worker').then((res) => {
+ self.postMessage({
+ type: 'module-and-worker:module',
+ data: res.module
+ })
+})
diff --git a/packages/playground/worker/emit-chunk-sub-worker.js b/packages/playground/worker/emit-chunk-sub-worker.js
new file mode 100644
index 00000000000000..5d20becc781dd7
--- /dev/null
+++ b/packages/playground/worker/emit-chunk-sub-worker.js
@@ -0,0 +1,8 @@
+Promise.all([
+ import('./module-and-worker'),
+ import('./modules/module2'),
+ import('./modules/module3')
+]).then((data) => {
+ const _data = { ...data[0], ...data[1], ...data[2] }
+ self.postMessage(_data)
+})
diff --git a/packages/playground/worker/index.html b/packages/playground/worker/index.html
index b3525da299ff5a..602aa3d06bfcac 100644
--- a/packages/playground/worker/index.html
+++ b/packages/playground/worker/index.html
@@ -1,3 +1,9 @@
+
worker template error match:
+
+ const worker = new Worker(new URL('./worker.js', import.meta.url))
+
+
+
Expected values:
Ping
@@ -20,113 +26,67 @@
0
-
new Worker(new Url('path', import.meta.url), { type: 'module' })
-
-
-
new SharedWorker(new Url('path', import.meta.url), { type: 'module' })
-
-
-
nested worker
-
-
-
new Worker(new Url('path', import.meta.url))
-
-
-
new Worker(new Url('path', import.meta.url), { type: 'classic' })
-
-
-
+ .classname {
+ color: green;
+ }
+
+
diff --git a/packages/playground/worker/module-and-worker.js b/packages/playground/worker/module-and-worker.js
new file mode 100644
index 00000000000000..659e556f08e4a6
--- /dev/null
+++ b/packages/playground/worker/module-and-worker.js
@@ -0,0 +1,5 @@
+import constant from './modules/module'
+
+self.postMessage(constant)
+
+export const module = 'module and worker'
diff --git a/packages/playground/worker/newUrl/module.js b/packages/playground/worker/modules/module.js
similarity index 100%
rename from packages/playground/worker/newUrl/module.js
rename to packages/playground/worker/modules/module.js
diff --git a/packages/playground/worker/modules/module1.js b/packages/playground/worker/modules/module1.js
new file mode 100644
index 00000000000000..191db09d29c44f
--- /dev/null
+++ b/packages/playground/worker/modules/module1.js
@@ -0,0 +1 @@
+export const msg1 = 'module1'
diff --git a/packages/playground/worker/modules/module2.js b/packages/playground/worker/modules/module2.js
new file mode 100644
index 00000000000000..60447933b8b16e
--- /dev/null
+++ b/packages/playground/worker/modules/module2.js
@@ -0,0 +1,3 @@
+export * from './module'
+export * from './module1'
+export const msg2 = 'module2'
diff --git a/packages/playground/worker/modules/module3.js b/packages/playground/worker/modules/module3.js
new file mode 100644
index 00000000000000..33355423bc030e
--- /dev/null
+++ b/packages/playground/worker/modules/module3.js
@@ -0,0 +1,2 @@
+export * from './module'
+export const msg3 = 'module3'
diff --git a/packages/playground/worker/test-plugin.tsx b/packages/playground/worker/modules/test-plugin.tsx
similarity index 100%
rename from packages/playground/worker/test-plugin.tsx
rename to packages/playground/worker/modules/test-plugin.tsx
diff --git a/packages/playground/worker/workerImport.js b/packages/playground/worker/modules/workerImport.js
similarity index 100%
rename from packages/playground/worker/workerImport.js
rename to packages/playground/worker/modules/workerImport.js
diff --git a/packages/playground/worker/my-worker.ts b/packages/playground/worker/my-worker.ts
index 550382be72c331..dd6061885128c7 100644
--- a/packages/playground/worker/my-worker.ts
+++ b/packages/playground/worker/my-worker.ts
@@ -1,5 +1,5 @@
-import { msg, mode } from './workerImport'
-import { bundleWithPlugin } from './test-plugin'
+import { msg, mode } from './modules/workerImport'
+import { bundleWithPlugin } from './modules/test-plugin'
self.onmessage = (e) => {
if (e.data === 'ping') {
diff --git a/packages/playground/worker/newUrl/classic-worker.js b/packages/playground/worker/newUrl/classic-worker.js
deleted file mode 100644
index 865810c76fbf85..00000000000000
--- a/packages/playground/worker/newUrl/classic-worker.js
+++ /dev/null
@@ -1,5 +0,0 @@
-importScripts('/classic.js')
-
-self.addEventListener('message', () => {
- self.postMessage(self.constant)
-})
diff --git a/packages/playground/worker/newUrl/url-worker.js b/packages/playground/worker/newUrl/url-worker.js
deleted file mode 100644
index afd91bfe613dc2..00000000000000
--- a/packages/playground/worker/newUrl/url-worker.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import constant from './module'
-
-self.postMessage(constant)
diff --git a/packages/playground/worker/package.json b/packages/playground/worker/package.json
index 131df8c4cbf336..ba4e7fe87e4a98 100644
--- a/packages/playground/worker/package.json
+++ b/packages/playground/worker/package.json
@@ -5,8 +5,20 @@
"scripts": {
"dev": "vite",
"build": "vite build",
- "debug": "node --inspect-brk ../../vite/bin/vite",
- "preview": "vite preview"
+ "preview": "vite preview",
+ "dev:es": "vite --config ./vite.config-es.js dev",
+ "build:es": "vite --config ./vite.config-es.js build",
+ "preview:es": "vite --config ./vite.config-es.js preview",
+ "dev:sourcemap": "cross-env WORKER_MODE=sourcemap vite --config ./vite.config-sourcemap.js dev",
+ "build:sourcemap": "cross-env WORKER_MODE=sourcemap vite --config ./vite.config-sourcemap.js build",
+ "preview:sourcemap": "cross-env WORKER_MODE=sourcemap vite --config ./vite.config-sourcemap.js preview",
+ "dev:sourcemap-hidden": "cross-env WORKER_MODE=hidden vite --config ./vite.config-sourcemap.js dev",
+ "build:sourcemap-hidden": "cross-env WORKER_MODE=hidden vite --config ./vite.config-sourcemap.js build",
+ "preview:sourcemap-hidden": "cross-env WORKER_MODE=hidden vite --config ./vite.config-sourcemap.js preview",
+ "dev:sourcemap-inline": "cross-env WORKER_MODE=inline vite --config ./vite.config-sourcemap.js dev",
+ "build:sourcemap-inline": "cross-env WORKER_MODE=inline vite --config ./vite.config-sourcemap.js build",
+ "preview:sourcemap-inline": "cross-env WORKER_MODE=inline vite --config ./vite.config-sourcemap.js preview",
+ "debug": "node --inspect-brk ../../vite/bin/vite"
},
"devDependencies": {
"@vitejs/plugin-vue-jsx": "workspace:*"
diff --git a/packages/playground/worker/possible-ts-output-worker.mjs b/packages/playground/worker/possible-ts-output-worker.mjs
index 2bcce3faa8a50e..25f1a447617cd9 100644
--- a/packages/playground/worker/possible-ts-output-worker.mjs
+++ b/packages/playground/worker/possible-ts-output-worker.mjs
@@ -1,4 +1,4 @@
-import { msg, mode } from './workerImport'
+import { msg, mode } from './modules/workerImport'
self.onmessage = (e) => {
if (e.data === 'ping') {
diff --git a/packages/playground/worker/sub-worker.js b/packages/playground/worker/sub-worker.js
index ab64b3667099bb..eff49dfbb46ba6 100644
--- a/packages/playground/worker/sub-worker.js
+++ b/packages/playground/worker/sub-worker.js
@@ -1,13 +1,5 @@
self.onmessage = (event) => {
if (event.data === 'ping') {
- self.postMessage('pong')
+ self.postMessage(`pong ${import.meta.url}`)
}
}
-const data = import('./workerImport')
-data.then((data) => {
- const { mode, msg } = data
- self.postMessage({
- mode,
- msg
- })
-})
diff --git a/packages/playground/worker/newUrl/url-shared-worker.js b/packages/playground/worker/url-shared-worker.js
similarity index 69%
rename from packages/playground/worker/newUrl/url-shared-worker.js
rename to packages/playground/worker/url-shared-worker.js
index f52de169243056..3535d5c277ec84 100644
--- a/packages/playground/worker/newUrl/url-shared-worker.js
+++ b/packages/playground/worker/url-shared-worker.js
@@ -1,4 +1,4 @@
-import constant from './module'
+import constant from './modules/module'
self.onconnect = (event) => {
const port = event.ports[0]
diff --git a/packages/playground/worker/url-worker.js b/packages/playground/worker/url-worker.js
new file mode 100644
index 00000000000000..c25cbefdff89ec
--- /dev/null
+++ b/packages/playground/worker/url-worker.js
@@ -0,0 +1 @@
+self.postMessage('A string' + import.meta.env.BASE_URL + import.meta.url)
diff --git a/packages/playground/worker/vite.config-es.js b/packages/playground/worker/vite.config-es.js
new file mode 100644
index 00000000000000..a65dece2d0db21
--- /dev/null
+++ b/packages/playground/worker/vite.config-es.js
@@ -0,0 +1,29 @@
+const vueJsx = require('@vitejs/plugin-vue-jsx')
+const vite = require('vite')
+const path = require('path')
+
+module.exports = vite.defineConfig({
+ base: '/es/',
+ enforce: 'pre',
+ worker: {
+ format: 'es',
+ plugins: [vueJsx()]
+ },
+ build: {
+ outDir: 'dist/es'
+ },
+ plugins: [
+ {
+ name: 'resolve-format-es',
+
+ transform(code, id) {
+ if (id.includes('main.js')) {
+ return code.replace(
+ `/* flag: will replace in vite config import("./format-es.js") */`,
+ `import("./main-format-es")`
+ )
+ }
+ }
+ }
+ ]
+})
diff --git a/packages/playground/worker/vite.config-sourcemap.js b/packages/playground/worker/vite.config-sourcemap.js
new file mode 100644
index 00000000000000..ea1c66a33a44d7
--- /dev/null
+++ b/packages/playground/worker/vite.config-sourcemap.js
@@ -0,0 +1,24 @@
+const vueJsx = require('@vitejs/plugin-vue-jsx')
+const vite = require('vite')
+
+module.exports = vite.defineConfig((sourcemap) => {
+ sourcemap = process.env.WORKER_MODE || sourcemap
+ if (sourcemap === 'sourcemap') {
+ sourcemap = true
+ }
+ return {
+ base: `/iife-${
+ typeof sourcemap === 'boolean' ? 'sourcemap' : 'sourcemap-' + sourcemap
+ }/`,
+ worker: {
+ format: 'iife',
+ plugins: [vueJsx()]
+ },
+ build: {
+ outDir: `dist/iife-${
+ typeof sourcemap === 'boolean' ? 'sourcemap' : 'sourcemap-' + sourcemap
+ }/`,
+ sourcemap: sourcemap
+ }
+ }
+})
diff --git a/packages/playground/worker/vite.config.js b/packages/playground/worker/vite.config.js
new file mode 100644
index 00000000000000..b7760bc4d7a240
--- /dev/null
+++ b/packages/playground/worker/vite.config.js
@@ -0,0 +1,13 @@
+const vueJsx = require('@vitejs/plugin-vue-jsx')
+const vite = require('vite')
+
+module.exports = vite.defineConfig({
+ base: '/iife/',
+ worker: {
+ format: 'iife',
+ plugins: [vueJsx()]
+ },
+ build: {
+ outDir: 'dist/iife'
+ }
+})
diff --git a/packages/playground/worker/vite.config.ts b/packages/playground/worker/vite.config.ts
deleted file mode 100644
index 6cef7d9cea0bed..00000000000000
--- a/packages/playground/worker/vite.config.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import vueJsx from '@vitejs/plugin-vue-jsx'
-import { defineConfig } from 'vite'
-
-export default defineConfig({
- worker: {
- format: 'es',
- plugins: [vueJsx()]
- }
-})
diff --git a/packages/playground/worker/worker/main-classic.js b/packages/playground/worker/worker/main-classic.js
new file mode 100644
index 00000000000000..4ef7776a56876e
--- /dev/null
+++ b/packages/playground/worker/worker/main-classic.js
@@ -0,0 +1,28 @@
+// prettier-ignore
+function text(el, text) {
+ document.querySelector(el).textContent = text
+}
+
+let classicWorker = new Worker(
+ new URL('../classic-worker.js', import.meta.url) /* , */
+ // test comment
+)
+
+// just test for case: ') ... ,' mean no worker options parmas
+classicWorker = new Worker(new URL('../classic-worker.js', import.meta.url))
+
+classicWorker.addEventListener('message', ({ data }) => {
+ text('.classic-worker', JSON.stringify(data))
+})
+classicWorker.postMessage('ping')
+
+const classicSharedWorker = new SharedWorker(
+ new URL('../classic-shared-worker.js', import.meta.url),
+ {
+ type: 'classic'
+ }
+)
+classicSharedWorker.port.addEventListener('message', (ev) => {
+ text('.classic-shared-worker', JSON.stringify(ev.data))
+})
+classicSharedWorker.port.start()
diff --git a/packages/playground/worker/worker/main-format-es.js b/packages/playground/worker/worker/main-format-es.js
new file mode 100644
index 00000000000000..801c13469151a3
--- /dev/null
+++ b/packages/playground/worker/worker/main-format-es.js
@@ -0,0 +1,41 @@
+// run when format es
+import NestedWorker from '../emit-chunk-nested-worker?worker'
+
+function text(el, text) {
+ document.querySelector(el).textContent = text
+}
+
+text('.format-es', 'format es:')
+
+const nestedWorker = new NestedWorker()
+const dataList = []
+nestedWorker.addEventListener('message', (ev) => {
+ dataList.push(ev.data)
+ text(
+ '.emti-chunk-worker',
+ JSON.stringify(
+ dataList.sort(
+ (a, b) => JSON.stringify(a).length - JSON.stringify(b).length
+ )
+ )
+ )
+})
+
+const dynamicImportWorker = new Worker(
+ new URL('../emit-chunk-dynamic-import-worker.js', import.meta.url),
+ {
+ type: 'module'
+ }
+)
+dynamicImportWorker.addEventListener('message', (ev) => {
+ text('.emti-chunk-dynamic-import-worker', JSON.stringify(ev.data))
+})
+
+const moduleWorker = new Worker(
+ new URL('../module-and-worker.js', import.meta.url),
+ { type: 'module' }
+)
+
+moduleWorker.addEventListener('message', (ev) => {
+ text('.module-and-worker-worker', JSON.stringify(ev.data))
+})
diff --git a/packages/playground/worker/worker/main-module.js b/packages/playground/worker/worker/main-module.js
new file mode 100644
index 00000000000000..417cf1728c4b09
--- /dev/null
+++ b/packages/playground/worker/worker/main-module.js
@@ -0,0 +1,85 @@
+import myWorker from '../my-worker?worker'
+import InlineWorker from '../my-worker?worker&inline'
+import mySharedWorker from '../my-shared-worker?sharedworker&name=shared'
+import TSOutputWorker from '../possible-ts-output-worker?worker'
+import NestedWorker from '../worker-nested-worker?worker'
+import { mode } from '../modules/workerImport'
+
+function text(el, text) {
+ document.querySelector(el).textContent = text
+}
+
+document.querySelector('.mode-true').textContent = mode
+
+const worker = new myWorker()
+worker.addEventListener('message', (e) => {
+ text('.pong', e.data.msg)
+ text('.mode', e.data.mode)
+ text('.bundle-with-plugin', e.data.bundleWithPlugin)
+})
+
+document.querySelector('.ping').addEventListener('click', () => {
+ worker.postMessage('ping')
+})
+
+const inlineWorker = new InlineWorker()
+inlineWorker.addEventListener('message', (e) => {
+ text('.pong-inline', e.data.msg)
+})
+
+document.querySelector('.ping-inline').addEventListener('click', () => {
+ console.log('111')
+ inlineWorker.postMessage('ping')
+})
+
+const sharedWorker = new mySharedWorker()
+document.querySelector('.tick-shared').addEventListener('click', () => {
+ sharedWorker.port.postMessage('tick')
+})
+
+sharedWorker.port.addEventListener('message', (event) => {
+ text('.tick-count', event.data)
+})
+
+sharedWorker.port.start()
+
+const tsOutputWorker = new TSOutputWorker()
+tsOutputWorker.addEventListener('message', (e) => {
+ text('.pong-ts-output', e.data.msg)
+})
+
+document.querySelector('.ping-ts-output').addEventListener('click', () => {
+ tsOutputWorker.postMessage('ping')
+})
+
+const nestedWorker = new NestedWorker()
+nestedWorker.addEventListener('message', (ev) => {
+ if (typeof ev.data === 'string') {
+ text('.nested-worker', JSON.stringify(ev.data))
+ }
+})
+nestedWorker.postMessage('ping')
+
+const workerOptions = { type: 'module' }
+// url import worker
+const w = new Worker(
+ new URL('../url-worker.js', import.meta.url),
+ /* @vite-ignore */ workerOptions
+)
+w.addEventListener('message', (ev) =>
+ text('.worker-import-meta-url', JSON.stringify(ev.data))
+)
+
+const genWorkerName = () => 'module'
+const w2 = new SharedWorker(
+ new URL('../url-shared-worker.js', import.meta.url),
+ {
+ /* @vite-ignore */
+ name: genWorkerName(),
+ type: 'module'
+ }
+)
+w2.port.addEventListener('message', (ev) => {
+ text('.shared-worker-import-meta-url', JSON.stringify(ev.data))
+})
+w2.port.start()
diff --git a/packages/playground/worker/worker/main.js b/packages/playground/worker/worker/main.js
new file mode 100644
index 00000000000000..953b5ef1bf3b53
--- /dev/null
+++ b/packages/playground/worker/worker/main.js
@@ -0,0 +1,3 @@
+/* flag: will replace in vite config import("./format-es.js") */
+import('./main-module')
+import('./main-classic')
diff --git a/packages/plugin-legacy/CHANGELOG.md b/packages/plugin-legacy/CHANGELOG.md
index e92ca1e12357fe..ced87d2efd665c 100644
--- a/packages/plugin-legacy/CHANGELOG.md
+++ b/packages/plugin-legacy/CHANGELOG.md
@@ -1,3 +1,17 @@
+## 1.8.0 (2022-03-30)
+
+* fix(deps): update all non-major dependencies (#6782) ([e38be3e](https://github.com/vitejs/vite/commit/e38be3e)), closes [#6782](https://github.com/vitejs/vite/issues/6782)
+* fix(deps): update all non-major dependencies (#7392) ([b63fc3b](https://github.com/vitejs/vite/commit/b63fc3b)), closes [#7392](https://github.com/vitejs/vite/issues/7392)
+* fix(plugin-legacy): always fallback legacy build when CSP (#6535) ([a118a1d](https://github.com/vitejs/vite/commit/a118a1d)), closes [#6535](https://github.com/vitejs/vite/issues/6535)
+* fix(plugin-legacy): polyfill latest features (#7514) ([cb388e2](https://github.com/vitejs/vite/commit/cb388e2)), closes [#7514](https://github.com/vitejs/vite/issues/7514)
+* fix(plugin-legacy): require Vite 2.8.0 (#6272) (#6869) ([997b8f1](https://github.com/vitejs/vite/commit/997b8f1)), closes [#6272](https://github.com/vitejs/vite/issues/6272) [#6869](https://github.com/vitejs/vite/issues/6869)
+* chore(deps): update all non-major dependencies (#6905) ([839665c](https://github.com/vitejs/vite/commit/839665c)), closes [#6905](https://github.com/vitejs/vite/issues/6905)
+* docs(vite-legacy): Note about using `regenerator-runtime` in Content Security Policy environment (#7 ([0fd6422](https://github.com/vitejs/vite/commit/0fd6422)), closes [#7234](https://github.com/vitejs/vite/issues/7234)
+* workflow: separate version bumping and publishing on release (#6879) ([fe8ef39](https://github.com/vitejs/vite/commit/fe8ef39)), closes [#6879](https://github.com/vitejs/vite/issues/6879)
+* release: plugin-legacy@1.7.1 ([19a58dd](https://github.com/vitejs/vite/commit/19a58dd))
+
+
+
## [1.7.1](https://github.com/vitejs/vite/compare/plugin-legacy@1.7.0...plugin-legacy@1.7.1) (2022-02-11)
### Bug Fixes
diff --git a/packages/plugin-legacy/README.md b/packages/plugin-legacy/README.md
index ec7e630c87755a..36da971c6a17c2 100644
--- a/packages/plugin-legacy/README.md
+++ b/packages/plugin-legacy/README.md
@@ -1,8 +1,6 @@
# @vitejs/plugin-legacy [![npm](https://img.shields.io/npm/v/@vitejs/plugin-legacy.svg)](https://npmjs.com/package/@vitejs/plugin-legacy)
-**Note: this plugin requires `vite@^2.0.0`**.
-
-Vite's default browser support baseline is [Native ESM](https://caniuse.com/es6-module). This plugin provides support for legacy browsers that do not support native ESM.
+Vite's default browser support baseline is [Native ESM](https://caniuse.com/es6-module). This plugin provides support for legacy browsers that do not support native ESM when building for production.
By default, this plugin will:
diff --git a/packages/plugin-legacy/index.js b/packages/plugin-legacy/index.js
index 626b48f85ea955..41f7157ebfc533 100644
--- a/packages/plugin-legacy/index.js
+++ b/packages/plugin-legacy/index.js
@@ -330,7 +330,10 @@ function viteLegacyPlugin(options = {}) {
loose: false,
useBuiltIns: needPolyfills ? 'usage' : false,
corejs: needPolyfills
- ? { version: 3, proposals: false }
+ ? {
+ version: require('core-js/package.json').version,
+ proposals: false
+ }
: undefined,
shippedProposals: true,
ignoreBrowserslistConfig: options.ignoreBrowserslistConfig
diff --git a/packages/plugin-legacy/package.json b/packages/plugin-legacy/package.json
index 6f3e44cc3e9fdd..aa8c478e4dae18 100644
--- a/packages/plugin-legacy/package.json
+++ b/packages/plugin-legacy/package.json
@@ -1,6 +1,6 @@
{
"name": "@vitejs/plugin-legacy",
- "version": "1.7.1",
+ "version": "1.8.0",
"license": "MIT",
"author": "Evan You",
"files": [
diff --git a/packages/plugin-react/CHANGELOG.md b/packages/plugin-react/CHANGELOG.md
index b1d1b8bddba63e..c05c0989d6beb4 100644
--- a/packages/plugin-react/CHANGELOG.md
+++ b/packages/plugin-react/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 1.3.0 (2022-03-30)
+
+* feat(plugin-react): adding jsxPure option (#7088) ([d451435](https://github.com/vitejs/vite/commit/d451435)), closes [#7088](https://github.com/vitejs/vite/issues/7088)
+* fix(deps): update all non-major dependencies (#6782) ([e38be3e](https://github.com/vitejs/vite/commit/e38be3e)), closes [#6782](https://github.com/vitejs/vite/issues/6782)
+* fix(deps): update all non-major dependencies (#7392) ([b63fc3b](https://github.com/vitejs/vite/commit/b63fc3b)), closes [#7392](https://github.com/vitejs/vite/issues/7392)
+* chore: fix publish, build vite before plugin-react and plugin-vue (#6988) ([620a9bd](https://github.com/vitejs/vite/commit/620a9bd)), closes [#6988](https://github.com/vitejs/vite/issues/6988)
+* chore(deps): update all non-major dependencies (#6905) ([839665c](https://github.com/vitejs/vite/commit/839665c)), closes [#6905](https://github.com/vitejs/vite/issues/6905)
+* workflow: separate version bumping and publishing on release (#6879) ([fe8ef39](https://github.com/vitejs/vite/commit/fe8ef39)), closes [#6879](https://github.com/vitejs/vite/issues/6879)
+
+
+
# [1.2.0](https://github.com/vitejs/vite/compare/plugin-react@1.1.4...plugin-react@1.2.0) (2022-02-09)
diff --git a/packages/plugin-react/README.md b/packages/plugin-react/README.md
index 588f947ec8b08c..e8d27d0e57242b 100644
--- a/packages/plugin-react/README.md
+++ b/packages/plugin-react/README.md
@@ -75,7 +75,7 @@ react({
})
```
-This option does not enable _code transformation_. That is handled by ESBuild.
+This option does not enable _code transformation_. That is handled by esbuild.
**Note:** TypeScript syntax is handled automatically.
diff --git a/packages/plugin-react/package.json b/packages/plugin-react/package.json
index f182a7f5a2fb10..e0230a4a61cd30 100644
--- a/packages/plugin-react/package.json
+++ b/packages/plugin-react/package.json
@@ -1,6 +1,6 @@
{
"name": "@vitejs/plugin-react",
- "version": "1.2.0",
+ "version": "1.3.0",
"license": "MIT",
"author": "Evan You",
"contributors": [
@@ -39,7 +39,7 @@
"@babel/plugin-transform-react-jsx-self": "^7.16.7",
"@babel/plugin-transform-react-jsx-source": "^7.16.7",
"@rollup/pluginutils": "^4.2.0",
- "react-refresh": "^0.11.0",
+ "react-refresh": "^0.12.0",
"resolve": "^1.22.0"
}
}
diff --git a/packages/plugin-react/src/fast-refresh.ts b/packages/plugin-react/src/fast-refresh.ts
index 70562bbbdfc5b7..4672e26f6264e3 100644
--- a/packages/plugin-react/src/fast-refresh.ts
+++ b/packages/plugin-react/src/fast-refresh.ts
@@ -1,10 +1,15 @@
import type { types as t } from '@babel/core'
import fs from 'fs'
+import path from 'path'
export const runtimePublicPath = '/@react-refresh'
-const runtimeFilePath = require.resolve(
- 'react-refresh/cjs/react-refresh-runtime.development.js'
+const reactRefreshDir = path.dirname(
+ require.resolve('react-refresh/package.json')
+)
+const runtimeFilePath = path.join(
+ reactRefreshDir,
+ 'cjs/react-refresh-runtime.development.js'
)
export const runtimeCode = `
diff --git a/packages/plugin-react/src/index.ts b/packages/plugin-react/src/index.ts
index afa1e2c5422da2..cefab59d94fe53 100644
--- a/packages/plugin-react/src/index.ts
+++ b/packages/plugin-react/src/index.ts
@@ -32,6 +32,12 @@ export interface Options {
* @default "react"
*/
jsxImportSource?: string
+ /**
+ * Set this to `true` to annotate the JSX factory with `\/* @__PURE__ *\/`.
+ * This option is ignored when `jsxRuntime` is not `"automatic"`.
+ * @default true
+ */
+ jsxPure?: boolean
/**
* Babel configuration applied in both dev and prod.
@@ -170,7 +176,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
if (isReactModule && filter(id)) {
useFastRefresh = true
plugins.push([
- await loadPlugin('react-refresh/babel.js'),
+ await loadPlugin('react-refresh/babel'),
{ skipEnvCheck: true }
])
}
@@ -195,7 +201,8 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
),
{
runtime: 'automatic',
- importSource: opts.jsxImportSource
+ importSource: opts.jsxImportSource,
+ pure: opts.jsxPure !== false
}
])
diff --git a/packages/plugin-vue-jsx/CHANGELOG.md b/packages/plugin-vue-jsx/CHANGELOG.md
index 43632e9a88ade8..3a1b9e681b45ea 100644
--- a/packages/plugin-vue-jsx/CHANGELOG.md
+++ b/packages/plugin-vue-jsx/CHANGELOG.md
@@ -1,3 +1,10 @@
+##
1.3.9 (2022-03-30)
+
+* fix(deps): update all non-major dependencies (#7392) ([b63fc3b](https://github.com/vitejs/vite/commit/b63fc3b)), closes [#7392](https://github.com/vitejs/vite/issues/7392)
+* chore(deps): update all non-major dependencies (#6905) ([839665c](https://github.com/vitejs/vite/commit/839665c)), closes [#6905](https://github.com/vitejs/vite/issues/6905)
+
+
+
## [1.3.8](https://github.com/vitejs/vite/compare/plugin-vue@2.2.4...plugin-vue@1.3.8) (2022-02-28)
diff --git a/packages/plugin-vue-jsx/package.json b/packages/plugin-vue-jsx/package.json
index ed807955ed0c87..c6a352eccc99a0 100644
--- a/packages/plugin-vue-jsx/package.json
+++ b/packages/plugin-vue-jsx/package.json
@@ -1,6 +1,6 @@
{
"name": "@vitejs/plugin-vue-jsx",
- "version": "1.3.8",
+ "version": "1.3.9",
"license": "MIT",
"author": "Evan You",
"files": [
diff --git a/packages/plugin-vue/CHANGELOG.md b/packages/plugin-vue/CHANGELOG.md
index 6fb47f160b1689..135daffbfaaa67 100644
--- a/packages/plugin-vue/CHANGELOG.md
+++ b/packages/plugin-vue/CHANGELOG.md
@@ -1,3 +1,26 @@
+##
2.3.1 (2022-03-30)
+
+* chore(plugin-vue): revert #7527, lower vite peer dep ([447bbeb](https://github.com/vitejs/vite/commit/447bbeb)), closes [#7527](https://github.com/vitejs/vite/issues/7527)
+
+
+
+## 2.3.0 (2022-03-30)
+
+* chore(plugin-vue): bump vite peer dep to 2.9.0 (#7472) ([12fd1d9](https://github.com/vitejs/vite/commit/12fd1d9)), closes [#7472](https://github.com/vitejs/vite/issues/7472)
+* feat(css): css.devSourcemap option (#7471) ([57f14cb](https://github.com/vitejs/vite/commit/57f14cb)), closes [#7471](https://github.com/vitejs/vite/issues/7471)
+* fix(plugin-vue): respect __VUE_PROD_DEVTOOLS__ setting (#4984) ([90e812a](https://github.com/vitejs/vite/commit/90e812a)), closes [#4984](https://github.com/vitejs/vite/issues/4984)
+
+
+
+## 2.3.0-beta.0 (2022-03-22)
+
+* fix(deps): update all non-major dependencies (#7392) ([b63fc3b](https://github.com/vitejs/vite/commit/b63fc3b)), closes [#7392](https://github.com/vitejs/vite/issues/7392)
+* feat: css sourcemap support during dev (#7173) ([38a655f](https://github.com/vitejs/vite/commit/38a655f)), closes [#7173](https://github.com/vitejs/vite/issues/7173)
+* chore(deps): update all non-major dependencies (#6905) ([839665c](https://github.com/vitejs/vite/commit/839665c)), closes [#6905](https://github.com/vitejs/vite/issues/6905)
+* docs(vue): add transformAssetUrls example (#7232) ([08e928c](https://github.com/vitejs/vite/commit/08e928c)), closes [#7232](https://github.com/vitejs/vite/issues/7232)
+
+
+
## [2.2.4](https://github.com/vitejs/vite/compare/plugin-vue@2.2.3...plugin-vue@2.2.4) (2022-02-28)
diff --git a/packages/plugin-vue/package.json b/packages/plugin-vue/package.json
index 6eccae93df840d..39b3bc87a8b1df 100644
--- a/packages/plugin-vue/package.json
+++ b/packages/plugin-vue/package.json
@@ -1,6 +1,6 @@
{
"name": "@vitejs/plugin-vue",
- "version": "2.2.4",
+ "version": "2.3.1",
"license": "MIT",
"author": "Evan You",
"files": [
diff --git a/packages/plugin-vue/src/index.ts b/packages/plugin-vue/src/index.ts
index 28a15996363285..7bdf63b700fa15 100644
--- a/packages/plugin-vue/src/index.ts
+++ b/packages/plugin-vue/src/index.ts
@@ -63,7 +63,9 @@ export interface ResolvedOptions extends Options {
compiler: typeof _compiler
root: string
sourceMap: boolean
+ cssDevSourcemap: boolean
devServer?: ViteDevServer
+ devToolsEnabled?: boolean
}
export default function vuePlugin(rawOptions: Options = {}): Plugin {
@@ -97,7 +99,9 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
customElement,
reactivityTransform,
root: process.cwd(),
- sourceMap: true
+ sourceMap: true,
+ cssDevSourcemap: false,
+ devToolsEnabled: process.env.NODE_ENV !== 'production'
}
// Temporal handling for 2.7 breaking change
@@ -135,7 +139,10 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
...options,
root: config.root,
sourceMap: config.command === 'build' ? !!config.build.sourcemap : true,
- isProduction: config.isProduction
+ cssDevSourcemap: config.css?.devSourcemap ?? false,
+ isProduction: config.isProduction,
+ devToolsEnabled:
+ !!config.define!.__VUE_PROD_DEVTOOLS__ || !config.isProduction
}
},
diff --git a/packages/plugin-vue/src/main.ts b/packages/plugin-vue/src/main.ts
index 7fb26fd39c6c03..44b1de74721efd 100644
--- a/packages/plugin-vue/src/main.ts
+++ b/packages/plugin-vue/src/main.ts
@@ -27,7 +27,7 @@ export async function transformMain(
ssr: boolean,
asCustomElement: boolean
) {
- const { devServer, isProduction } = options
+ const { devServer, isProduction, devToolsEnabled } = options
// prev descriptor is only set and used for hmr
const prevDescriptor = getPrevDescriptor(filename)
@@ -102,9 +102,12 @@ export async function transformMain(
if (hasScoped) {
attachedProps.push([`__scopeId`, JSON.stringify(`data-v-${descriptor.id}`)])
}
- if (devServer && !isProduction) {
+ if (devToolsEnabled || (devServer && !isProduction)) {
// expose filename during serve for devtools to pickup
- attachedProps.push([`__file`, JSON.stringify(filename)])
+ attachedProps.push([
+ `__file`,
+ JSON.stringify(isProduction ? path.basename(filename) : filename)
+ ])
}
// HMR
diff --git a/packages/plugin-vue/src/style.ts b/packages/plugin-vue/src/style.ts
index c124f3ec744e4f..cab75791bd54ec 100644
--- a/packages/plugin-vue/src/style.ts
+++ b/packages/plugin-vue/src/style.ts
@@ -23,13 +23,17 @@ export async function transformStyle(
isProd: options.isProduction,
source: code,
scoped: block.scoped,
- postcssOptions: {
- map: {
- from: filename,
- inline: false,
- annotation: false
- }
- }
+ ...(options.cssDevSourcemap
+ ? {
+ postcssOptions: {
+ map: {
+ from: filename,
+ inline: false,
+ annotation: false
+ }
+ }
+ }
+ : {})
})
if (result.errors.length) {
diff --git a/packages/vite/CHANGELOG.md b/packages/vite/CHANGELOG.md
index 1809b04a4e8c92..0f91a004602caa 100644
--- a/packages/vite/CHANGELOG.md
+++ b/packages/vite/CHANGELOG.md
@@ -1,48 +1,112 @@
-## 2.9.0-beta.6 (2022-03-22)
+##
2.9.1 (2022-03-31)
+* fix: allow port 0 to be provided to server (#7530) ([173e4c9](https://github.com/vitejs/vite/commit/173e4c9)), closes [#7530](https://github.com/vitejs/vite/issues/7530)
+* fix: brotli let for reassignment (#7544) ([d0253d7](https://github.com/vitejs/vite/commit/d0253d7)), closes [#7544](https://github.com/vitejs/vite/issues/7544)
+* fix: dynamic import warning with @vite-ignore (#7533) ([29c1ec0](https://github.com/vitejs/vite/commit/29c1ec0)), closes [#7533](https://github.com/vitejs/vite/issues/7533)
+* fix: remove unneeded skipping optimization log (#7531) ([41fa2f5](https://github.com/vitejs/vite/commit/41fa2f5)), closes [#7531](https://github.com/vitejs/vite/issues/7531)
+* docs(changelog): fix raw glob imports syntax (#7540) ([87fbe13](https://github.com/vitejs/vite/commit/87fbe13)), closes [#7540](https://github.com/vitejs/vite/issues/7540)
+* chore: 2.9 release notes (#7525) ([4324f48](https://github.com/vitejs/vite/commit/4324f48)), closes [#7525](https://github.com/vitejs/vite/issues/7525)
-## 2.9.0-beta.5 (2022-03-22)
+# [2.9.0](https://github.com/vitejs/vite/compare/v2.8.6...v2.9.0) (2022-03-30)
-* fix: avoid mangling code from incorrect magic-string usage (#7397) ([68d76c9](https://github.com/vitejs/vite/commit/68d76c9)), closes [#7397](https://github.com/vitejs/vite/issues/7397)
-* fix(config): server restart on config dependencies changed on windows (#7366) ([c43467a](https://github.com/vitejs/vite/commit/c43467a)), closes [#7366](https://github.com/vitejs/vite/issues/7366)
-* fix(deps): update all non-major dependencies (#7392) ([b63fc3b](https://github.com/vitejs/vite/commit/b63fc3b)), closes [#7392](https://github.com/vitejs/vite/issues/7392)
-* feat: css sourcemap support during dev (#7173) ([38a655f](https://github.com/vitejs/vite/commit/38a655f)), closes [#7173](https://github.com/vitejs/vite/issues/7173)
+### Faster Cold Start
+Before 2.9, the first time dev was run on a project Vite needed to perform a scan phase to discover dependencies and then pre-bundle them before starting the server. In 2.9 both scanning [#7379](https://github.com/vitejs/vite/issues/7379) and pre-bundling [#6758](https://github.com/vitejs/vite/issues/6758) of dependencies are now non-blocking, so the server starts right away during cold start. We also now allow requests to flow through the pipeline improving initial cold start load speed and increasing the chances of discovering new missing dependencies when re-processing and letting Vite populate the module graph and the browser to process files. In many cases, there is also no need to full-reload the page when new dependencies are discovered.
+### CSS Sourcemap support during dev (experimental)
-## 2.9.0-beta.4 (2022-03-19)
+Vite now supports CSS sourcemaps [#7173](https://github.com/vitejs/vite/issues/7173). This feature is still experimental, and it is disabled by default to avoid incurring a performance penalty for users that don't need it. To enable it, set [css.devSourcemap](https://vitejs.dev/config/#css-devsourcemap) to `true`.
-* fix: add version to optimized chunks, fix #7323 (#7350) ([1be1db6](https://github.com/vitejs/vite/commit/1be1db6)), closes [#7323](https://github.com/vitejs/vite/issues/7323) [#7350](https://github.com/vitejs/vite/issues/7350)
-* fix: browser cache of newly discovered deps (#7378) ([392a0de](https://github.com/vitejs/vite/commit/392a0de)), closes [#7378](https://github.com/vitejs/vite/issues/7378)
-* fix: do not warn (about not being able to bundle non module scripts) when src is an external url (#7 ([0646fe8](https://github.com/vitejs/vite/commit/0646fe8)), closes [#7380](https://github.com/vitejs/vite/issues/7380)
-* fix: overwrite deps info browserHash only on commit (#7359) ([1e9615d](https://github.com/vitejs/vite/commit/1e9615d)), closes [#7359](https://github.com/vitejs/vite/issues/7359)
-* chore: fix typo in comment (#7370) ([e682863](https://github.com/vitejs/vite/commit/e682863)), closes [#7370](https://github.com/vitejs/vite/issues/7370)
-* chore: update es-module-lexer (#7357) ([fde0f3c](https://github.com/vitejs/vite/commit/fde0f3c)), closes [#7357](https://github.com/vitejs/vite/issues/7357)
-* chore(deps): update all non-major dependencies (#6905) ([839665c](https://github.com/vitejs/vite/commit/839665c)), closes [#6905](https://github.com/vitejs/vite/issues/6905)
+### Avoid splitting vendor chunks by default
+Vite's default chunking strategy was a good fit for most SPAs, but it wasn't ideal in some other use cases. Vite doesn't have enough context to make the best decision here, so in Vite 2.9 the previous chunking strategy is now [opt-in](https://vitejs.dev/guide/build.html#chunking-strategy) [#6534](https://github.com/vitejs/vite/issues/6534) and Vite will no longer split vendor libs in a separate chunk.
+### Web Workers enhancements
-## 2.9.0-beta.3 (2022-03-16)
+Web Workers now supports source map generation (see [#5417](https://github.com/vitejs/vite/issues/5417)). The implementation is also now more robust, fixing several issues encountered in previous versions ([#6599](https://github.com/vitejs/vite/issues/6599)).
-* fix: delayed full page reload (#7347) ([fa0820a](https://github.com/vitejs/vite/commit/fa0820a)), closes [#7347](https://github.com/vitejs/vite/issues/7347)
-* fix: early discovery of missing deps, fix #7333 (#7346) ([7d2f37c](https://github.com/vitejs/vite/commit/7d2f37c)), closes [#7333](https://github.com/vitejs/vite/issues/7333) [#7346](https://github.com/vitejs/vite/issues/7346)
-* fix: unhandled exception on eager transformRequest (#7345) ([c3260a4](https://github.com/vitejs/vite/commit/c3260a4)), closes [#7345](https://github.com/vitejs/vite/issues/7345)
-* fix: update to esbuild 0.14.27, fix #6994 (#7320) ([65aaeee](https://github.com/vitejs/vite/commit/65aaeee)), closes [#6994](https://github.com/vitejs/vite/issues/6994) [#7320](https://github.com/vitejs/vite/issues/7320)
-* chore: comment typo (#7344) ([61df324](https://github.com/vitejs/vite/commit/61df324)), closes [#7344](https://github.com/vitejs/vite/issues/7344)
+### Raw Glob Imports
+
+Glob imports support for the `raw` modifier syntax has changed to using `{ as: 'raw' }`, which works in the same way as the `?raw` suffix in regular imports:
+```js
+const examples = import.meta.globEager('./examples/*.html', { as: 'raw' })
+```
+The `{ assert: { type: 'raw' }}` syntax introduced in v2.8 has been deprecated. See [#7017](https://github.com/vitejs/vite/issues/7017) for more information.
-## 2.9.0-beta.2 (2022-03-14)
+### `envDir` changes
-* fix: `ssrExternal` should not skip nested dependencies (#7154) ([f8f934a](https://github.com/vitejs/vite/commit/f8f934a)), closes [#7154](https://github.com/vitejs/vite/issues/7154)
-* fix: dep with dynamic import wrong error log (#7313) ([769f535](https://github.com/vitejs/vite/commit/769f535)), closes [#7313](https://github.com/vitejs/vite/issues/7313)
+The `envDir` now correctly loads `.env` files in the specified directory only (defaults to `root`). Previously, it would load files above the directory, which imposed security issues. If you had relied on the previous behaviour, make sure you move your `.env` files to the correct directory, or configure the `envDir` option.
+
+### New tools for Plugin and Framework Authors
+
+#### Client Server Communication API
+
+Vite now provides utilities for plugins to help handle the communication with clients connected to Vite's server [#7437](https://github.com/vitejs/vite/issues/7437). Reusing the open WebSocket connection between the server and clients several use cases can be simplified ([vite-plugin-inspect](https://github.com/antfu/vite-plugin-inspect), [SliDev](https://sli.dev), and many others). Check out the [Client Server Communication docs](https://vitejs.dev/guide/api-plugin.html#client-server-communication) for more information.
+
+```js
+// Send a message from the client to the server
+if (import.meta.hot) {
+ import.meta.hot.send('my:from-client', { msg: 'Hey!' })
+}
+```
+
+```js
+// And listen to client messages in a plugin
+ configureServer(server) {
+ server.ws.on('my:from-client', (data, client) => {
+ console.log('Message from client:', data.msg) // Hey!
+ // ...
+ })
+ }
+```
+
+#### `importedCss` and `importedAssets` to RenderedChunk type
+Replace the internal `chunkToEmittedCssFileMap` and `chunkToEmittedAssetsMap` variables with public properties added by Vite to `RenderedChunk` objects in the `renderChunk` phase. These is useful for Vite-based frameworks that generate their own HTML. See [#6629](https://github.com/vitejs/vite/issues/6629).
+#### Optimize Custom Extensions (experimental)
-## 2.9.0-beta.1 (2022-03-14)
+A new `optimizeDeps.extensions: string[]` option is available to enable pre-bundling of custom extensions. A respective esbuild plugin is required to handle that extension. e.g. `['.svelte', '.svelte.md']`. See [#6801](https://github.com/vitejs/vite/issues/6801) for more information.
+
+### Bug Fixes
+
+* fix: build path error on Windows (#7383) ([e3c7c7a](https://github.com/vitejs/vite/commit/e3c7c7a)), closes [#7383](https://github.com/vitejs/vite/issues/7383)
+* fix: import url worker two times (#7468) ([f05a813](https://github.com/vitejs/vite/commit/f05a813)), closes [#7468](https://github.com/vitejs/vite/issues/7468)
+* fix: import with query with exports/browser field (#7098) ([9ce6732](https://github.com/vitejs/vite/commit/9ce6732)), closes [#7098](https://github.com/vitejs/vite/issues/7098)
+* fix: make @fs URLs work with special characters (#7510) ([2b7dad1](https://github.com/vitejs/vite/commit/2b7dad1)), closes [#7510](https://github.com/vitejs/vite/issues/7510)
+* fix: tailwind css sourcemap warning (#7480) ([90df0bb](https://github.com/vitejs/vite/commit/90df0bb)), closes [#7480](https://github.com/vitejs/vite/issues/7480)
+* fix: worker match only run in js (#7500) ([9481c7d](https://github.com/vitejs/vite/commit/9481c7d)), closes [#7500](https://github.com/vitejs/vite/issues/7500)
+* fix: Correctly process urls when they are rewritten to contain space (#7452) ([9ee2cf6](https://github.com/vitejs/vite/commit/9ee2cf6)), closes [#7452](https://github.com/vitejs/vite/issues/7452)
+* fix: custom event payload type (#7498) ([28b0660](https://github.com/vitejs/vite/commit/28b0660)), closes [#7498](https://github.com/vitejs/vite/issues/7498)
+* fix: handle relative path glob raw import, fix #7307 (#7371) ([7f8dc58](https://github.com/vitejs/vite/commit/7f8dc58)), closes [#7307](https://github.com/vitejs/vite/issues/7307) [#7371](https://github.com/vitejs/vite/issues/7371)
+* fix: import.meta.url in worker (#7464) ([8ac4b12](https://github.com/vitejs/vite/commit/8ac4b12)), closes [#7464](https://github.com/vitejs/vite/issues/7464)
+* fix: optimizeDeps.entries default ignore paths (#7469) ([4c95e99](https://github.com/vitejs/vite/commit/4c95e99)), closes [#7469](https://github.com/vitejs/vite/issues/7469)
+* fix: errors in worker handling (#7236) ([77dc1a1](https://github.com/vitejs/vite/commit/77dc1a1)), closes [#7236](https://github.com/vitejs/vite/issues/7236)
+* fix: consider undefined port when checking port (#7318) ([c7fc7c3](https://github.com/vitejs/vite/commit/c7fc7c3)), closes [#7318](https://github.com/vitejs/vite/issues/7318)
+* fix: inline style css sourcemap (#7434) ([47668b5](https://github.com/vitejs/vite/commit/47668b5)), closes [#7434](https://github.com/vitejs/vite/issues/7434)
+* fix: sourcemap missing source files warning with cached vue (#7442) ([a2ce20d](https://github.com/vitejs/vite/commit/a2ce20d)), closes [#7442](https://github.com/vitejs/vite/issues/7442)
+* fix: update tsconfck to 1.2.1 (#7424) ([a90b03b](https://github.com/vitejs/vite/commit/a90b03b)), closes [#7424](https://github.com/vitejs/vite/issues/7424)
+* fix: virtual html sourcemap warning (#7440) ([476786b](https://github.com/vitejs/vite/commit/476786b)), closes [#7440](https://github.com/vitejs/vite/issues/7440)
+* fix(less): empty less file error (#7412) ([0535c70](https://github.com/vitejs/vite/commit/0535c70)), closes [#7412](https://github.com/vitejs/vite/issues/7412)
+* fix(resolve): skip `module` field when the importer is a `require` call (#7438) ([fe4c1ed](https://github.com/vitejs/vite/commit/fe4c1ed)), closes [#7438](https://github.com/vitejs/vite/issues/7438)
+* fix: avoid mangling code from incorrect magic-string usage (#7397) ([68d76c9](https://github.com/vitejs/vite/commit/68d76c9)), closes [#7397](https://github.com/vitejs/vite/issues/7397)
+* fix(config): server restart on config dependencies changed on windows (#7366) ([c43467a](https://github.com/vitejs/vite/commit/c43467a)), closes [#7366](https://github.com/vitejs/vite/issues/7366)
+* fix(deps): update all non-major dependencies (#7392) ([b63fc3b](https://github.com/vitejs/vite/commit/b63fc3b)), closes [#7392](https://github.com/vitejs/vite/issues/7392)
+* fix: add version to optimized chunks, fix #7323 (#7350) ([1be1db6](https://github.com/vitejs/vite/commit/1be1db6)), closes [#7323](https://github.com/vitejs/vite/issues/7323) [#7350](https://github.com/vitejs/vite/issues/7350)
+* fix: browser cache of newly discovered deps (#7378) ([392a0de](https://github.com/vitejs/vite/commit/392a0de)), closes [#7378](https://github.com/vitejs/vite/issues/7378)
+* fix: do not warn (about not being able to bundle non module scripts) when src is an external url (#7 ([0646fe8](https://github.com/vitejs/vite/commit/0646fe8)), closes [#7380](https://github.com/vitejs/vite/issues/7380)
+* fix: overwrite deps info browserHash only on commit (#7359) ([1e9615d](https://github.com/vitejs/vite/commit/1e9615d)), closes [#7359](https://github.com/vitejs/vite/issues/7359)
+* fix: delayed full page reload (#7347) ([fa0820a](https://github.com/vitejs/vite/commit/fa0820a)), closes [#7347](https://github.com/vitejs/vite/issues/7347)
+* fix: early discovery of missing deps, fix #7333 (#7346) ([7d2f37c](https://github.com/vitejs/vite/commit/7d2f37c)), closes [#7333](https://github.com/vitejs/vite/issues/7333) [#7346](https://github.com/vitejs/vite/issues/7346)
+* fix: unhandled exception on eager transformRequest (#7345) ([c3260a4](https://github.com/vitejs/vite/commit/c3260a4)), closes [#7345](https://github.com/vitejs/vite/issues/7345)
+* fix: update to esbuild 0.14.27, fix #6994 (#7320) ([65aaeee](https://github.com/vitejs/vite/commit/65aaeee)), closes [#6994](https://github.com/vitejs/vite/issues/6994) [#7320](https://github.com/vitejs/vite/issues/7320)
+* fix: `ssrExternal` should not skip nested dependencies (#7154) ([f8f934a](https://github.com/vitejs/vite/commit/f8f934a)), closes [#7154](https://github.com/vitejs/vite/issues/7154)
+* fix: dep with dynamic import wrong error log (#7313) ([769f535](https://github.com/vitejs/vite/commit/769f535)), closes [#7313](https://github.com/vitejs/vite/issues/7313)
* fix: avoid caching transform result of invalidated module (#7254) ([2d7ba72](https://github.com/vitejs/vite/commit/2d7ba72)), closes [#7254](https://github.com/vitejs/vite/issues/7254)
* fix: dont replace define in json (#7294) ([fc5c937](https://github.com/vitejs/vite/commit/fc5c937)), closes [#7294](https://github.com/vitejs/vite/issues/7294)
* fix: main browserHash after stable optimization rerun (#7284) ([98eefa8](https://github.com/vitejs/vite/commit/98eefa8)), closes [#7284](https://github.com/vitejs/vite/issues/7284)
@@ -53,15 +117,6 @@
* fix: use relative paths in _metadata.json (#7299) ([8b945f5](https://github.com/vitejs/vite/commit/8b945f5)), closes [#7299](https://github.com/vitejs/vite/issues/7299)
* fix(asset): allow non-existent url (#7306) ([6bc45a2](https://github.com/vitejs/vite/commit/6bc45a2)), closes [#7306](https://github.com/vitejs/vite/issues/7306)
* fix(hmr): hmr style tag no support in html (#7262) ([fae120a](https://github.com/vitejs/vite/commit/fae120a)), closes [#7262](https://github.com/vitejs/vite/issues/7262)
-* chore: clarify writableEnded guard comment (#7256) ([dddda1e](https://github.com/vitejs/vite/commit/dddda1e)), closes [#7256](https://github.com/vitejs/vite/issues/7256)
-* chore: new line for non-existent url (#7308) ([522faf8](https://github.com/vitejs/vite/commit/522faf8)), closes [#7308](https://github.com/vitejs/vite/issues/7308)
-* chore: remove unused code (#7303) ([467512b](https://github.com/vitejs/vite/commit/467512b)), closes [#7303](https://github.com/vitejs/vite/issues/7303)
-* feat: expose ssrRewriteStacktrace (#7091) ([d4ae45d](https://github.com/vitejs/vite/commit/d4ae45d)), closes [#7091](https://github.com/vitejs/vite/issues/7091)
-
-
-
-## 2.9.0-beta.0 (2022-03-09)
-
* fix: `import.meta.url` should not throw (#7219) ([5de3a98](https://github.com/vitejs/vite/commit/5de3a98)), closes [#7219](https://github.com/vitejs/vite/issues/7219)
* fix: allow `localhost` as a valid hostname (#7092) ([4194cce](https://github.com/vitejs/vite/commit/4194cce)), closes [#7092](https://github.com/vitejs/vite/issues/7092)
* fix: build optimize deps metada location (#7214) ([dc46adf](https://github.com/vitejs/vite/commit/dc46adf)), closes [#7214](https://github.com/vitejs/vite/issues/7214)
@@ -87,18 +142,93 @@
* fix(server): base middleware redirect with search and hash (#6574) ([a516e85](https://github.com/vitejs/vite/commit/a516e85)), closes [#6574](https://github.com/vitejs/vite/issues/6574)
* fix(server): ensure consistency for url to file mapping in importAnalysis and static middleware (#65 ([b214115](https://github.com/vitejs/vite/commit/b214115)), closes [#6518](https://github.com/vitejs/vite/issues/6518)
* fix(ssr): bypass missing resolve error in SSR (#7164) ([a4927c5](https://github.com/vitejs/vite/commit/a4927c5)), closes [#7164](https://github.com/vitejs/vite/issues/7164)
-* chore: replace SourceMapConsumer with trace-mapping (#6746) ([ed4d191](https://github.com/vitejs/vite/commit/ed4d191)), closes [#6746](https://github.com/vitejs/vite/issues/6746)
+
+
+### Features
+
+* feat(worker): Add sourcemap support for worker bundles (#5417) ([465b6b9](https://github.com/vitejs/vite/commit/465b6b9)), closes [#5417](https://github.com/vitejs/vite/issues/5417)
+* feat(type): support typing for custom events (#7476) ([50a8765](https://github.com/vitejs/vite/commit/50a8765)), closes [#7476](https://github.com/vitejs/vite/issues/7476)
+* refactor(types): share hot context type (#7475) ([64ddff0](https://github.com/vitejs/vite/commit/64ddff0)), closes [#7475](https://github.com/vitejs/vite/issues/7475)
+* feat: support importing css with ?raw (#5796) ([fedb106](https://github.com/vitejs/vite/commit/fedb106)), closes [#5796](https://github.com/vitejs/vite/issues/5796)
+* feat(css): css.devSourcemap option (#7471) ([57f14cb](https://github.com/vitejs/vite/commit/57f14cb)), closes [#7471](https://github.com/vitejs/vite/issues/7471)
+* feat(dev): expose APIs for client-server communication (#7437) ([e29ea8e](https://github.com/vitejs/vite/commit/e29ea8e)), closes [#7437](https://github.com/vitejs/vite/issues/7437)
+* feat: hide optimized deps found during scan phase logs (#7419) ([f4934e8](https://github.com/vitejs/vite/commit/f4934e8)), closes [#7419](https://github.com/vitejs/vite/issues/7419)
+* feat: non-blocking scanning of dependencies (#7379) ([676f545](https://github.com/vitejs/vite/commit/676f545)), closes [#7379](https://github.com/vitejs/vite/issues/7379)
+* feat: css sourcemap support during dev (#7173) ([38a655f](https://github.com/vitejs/vite/commit/38a655f)), closes [#7173](https://github.com/vitejs/vite/issues/7173)
+* feat: expose ssrRewriteStacktrace (#7091) ([d4ae45d](https://github.com/vitejs/vite/commit/d4ae45d)), closes [#7091](https://github.com/vitejs/vite/issues/7091)
* feat: add `importedCss` and `importedAssets` to RenderedChunk type (#6629) ([8d0fc90](https://github.com/vitejs/vite/commit/8d0fc90)), closes [#6629](https://github.com/vitejs/vite/issues/6629)
* feat: non-blocking pre bundling of dependencies (#6758) ([24bb3e4](https://github.com/vitejs/vite/commit/24bb3e4)), closes [#6758](https://github.com/vitejs/vite/issues/6758)
* feat: optimize custom extensions (#6801) ([c11af23](https://github.com/vitejs/vite/commit/c11af23)), closes [#6801](https://github.com/vitejs/vite/issues/6801)
* feat: show all prebundle deps when debug (#6726) ([e626055](https://github.com/vitejs/vite/commit/e626055)), closes [#6726](https://github.com/vitejs/vite/issues/6726)
-* feat(config): hmr add disable port config (#6624) ([ce07a0a](https://github.com/vitejs/vite/commit/ce07a0a)), closes [#6624](https://github.com/vitejs/vite/issues/6624)
* feat(glob): import.meta.glob support alias path (#6526) ([86882ad](https://github.com/vitejs/vite/commit/86882ad)), closes [#6526](https://github.com/vitejs/vite/issues/6526)
* feat(perf): tsconfck perf improvement (#7055) ([993ea39](https://github.com/vitejs/vite/commit/993ea39)), closes [#7055](https://github.com/vitejs/vite/issues/7055)
* feat(worker): bundle worker emit asset file (#6599) ([0ade335](https://github.com/vitejs/vite/commit/0ade335)), closes [#6599](https://github.com/vitejs/vite/issues/6599)
* refactor: avoid splitting vendor chunk by default (#6534) ([849e845](https://github.com/vitejs/vite/commit/849e845)), closes [#6534](https://github.com/vitejs/vite/issues/6534)
+### Beta Changelogs
+
+
+#### [2.9.0-beta.11](https://github.com/vitejs/vite/compare/v2.9.0-beta.10...v2.9.0-beta.11) (2022-03-29)
+
+See [2.9.0-beta.11 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.11/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.10](https://github.com/vitejs/vite/compare/v2.9.0-beta.9...v2.9.0-beta.10) (2022-03-28)
+
+See [2.9.0-beta.10 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.10/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.9](https://github.com/vitejs/vite/compare/v2.9.0-beta.8...v2.9.0-beta.9) (2022-03-26)
+
+See [2.9.0-beta.9 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.9/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.8](https://github.com/vitejs/vite/compare/v2.9.0-beta.7...v2.9.0-beta.8) (2022-03-24)
+
+See [2.9.0-beta.8 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.8/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.7](https://github.com/vitejs/vite/compare/v2.9.0-beta.6...v2.9.0-beta.7) (2022-03-23)
+
+See [2.9.0-beta.7 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.7/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.6](https://github.com/vitejs/vite/compare/v2.9.0-beta.5...v2.9.0-beta.6) (2022-03-22)
+
+See [2.9.0-beta.6 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.6/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.5](https://github.com/vitejs/vite/compare/v2.9.0-beta.4...v2.9.0-beta.5) (2022-03-22)
+
+See [2.9.0-beta.5 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.5/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.4](https://github.com/vitejs/vite/compare/v2.9.0-beta.3...v2.9.0-beta.4) (2022-03-19)
+
+See [2.9.0-beta.4 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.4/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.3](https://github.com/vitejs/vite/compare/v2.9.0-beta.2...v2.9.0-beta.3) (2022-03-16)
+
+See [2.9.0-beta.3 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.3/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.2](https://github.com/vitejs/vite/compare/v2.9.0-beta.1...v2.9.0-beta.2) (2022-03-14)
+
+See [2.9.0-beta.2 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.2/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.1](https://github.com/vitejs/vite/compare/v2.9.0-beta.0...v2.9.0-beta.1) (2022-03-14)
+
+See [2.9.0-beta.1 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.1/packages/vite/CHANGELOG.md)
+
+
+#### [2.9.0-beta.0](https://github.com/vitejs/vite/compare/v2.8.6...v2.9.0-beta.0) (2022-03-09)
+
+See [2.9.0-beta.0 changelog](https://github.com/vitejs/vite/blob/v2.9.0-beta.0/packages/vite/CHANGELOG.md)
+
+
## [2.8.6](https://github.com/vitejs/vite/compare/v2.8.5...v2.8.6) (2022-03-01)
@@ -198,7 +328,7 @@
### Default preview port
-New default port for `vite preview` is 4173 (avoid conflicts in MacOS that took over the 5000 port)
+New default port for `vite preview` is 4173 (avoid conflicts in macOS that took over the 5000 port)
### Workers using standard syntax
diff --git a/packages/vite/package.json b/packages/vite/package.json
index c1aa489f340fc0..d2a351c6aa0869 100644
--- a/packages/vite/package.json
+++ b/packages/vite/package.json
@@ -1,6 +1,6 @@
{
"name": "vite",
- "version": "2.9.0-beta.6",
+ "version": "2.9.1",
"license": "MIT",
"author": "Evan You",
"description": "Native-ESM powered web dev build tool",
@@ -57,7 +57,7 @@
"@babel/types": "^7.17.0",
"@jridgewell/trace-mapping": "^0.3.4",
"@rollup/plugin-alias": "^3.1.9",
- "@rollup/plugin-commonjs": "^21.0.2",
+ "@rollup/plugin-commonjs": "^21.0.3",
"@rollup/plugin-dynamic-import-vars": "^1.4.2",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "13.1.3",
@@ -74,7 +74,7 @@
"@types/node": "^16.11.26",
"@types/resolve": "^1.20.1",
"@types/sass": "~1.43.1",
- "@types/stylus": "^0.48.36",
+ "@types/stylus": "^0.48.37",
"@types/ws": "^8.5.3",
"@vue/compiler-dom": "^3.2.31",
"acorn": "^8.7.0",
@@ -88,7 +88,7 @@
"debug": "^4.3.4",
"dotenv": "^14.3.2",
"dotenv-expand": "^5.1.0",
- "es-module-lexer": "^0.10.4",
+ "es-module-lexer": "^0.10.5",
"estree-walker": "^2.0.2",
"etag": "^1.8.1",
"fast-glob": "^3.2.11",
@@ -96,15 +96,15 @@
"json5": "^2.2.1",
"launch-editor-middleware": "^2.3.0",
"magic-string": "^0.26.1",
- "micromatch": "^4.0.4",
+ "micromatch": "^4.0.5",
"mrmime": "^1.0.0",
- "node-forge": "^1.3.0",
+ "node-forge": "^1.3.1",
"okie": "^1.0.1",
"open": "^8.4.0",
"periscopic": "^2.0.3",
"picocolors": "^1.0.0",
- "postcss-import": "^14.0.2",
- "postcss-load-config": "^3.1.3",
+ "postcss-import": "^14.1.0",
+ "postcss-load-config": "^3.1.4",
"postcss-modules": "^4.3.1",
"resolve.exports": "^1.1.0",
"rollup-plugin-license": "^2.6.1",
@@ -113,7 +113,7 @@
"source-map-support": "^0.5.21",
"strip-ansi": "^6.0.1",
"terser": "^5.12.1",
- "tsconfck": "^1.2.0",
+ "tsconfck": "^1.2.2",
"tslib": "^2.3.1",
"types": "link:./types",
"ws": "^8.5.0"
diff --git a/packages/vite/src/client/client.ts b/packages/vite/src/client/client.ts
index a9e8fb639de958..420d084ef9a981 100644
--- a/packages/vite/src/client/client.ts
+++ b/packages/vite/src/client/client.ts
@@ -1,12 +1,6 @@
-import type {
- ErrorPayload,
- FullReloadPayload,
- HMRPayload,
- PrunePayload,
- Update,
- UpdatePayload
-} from 'types/hmrPayload'
-import type { CustomEventName } from 'types/customEvent'
+import type { ErrorPayload, HMRPayload, Update } from 'types/hmrPayload'
+import type { ViteHotContext } from 'types/hot'
+import type { InferCustomEventPayload } from 'types/customEvent'
import { ErrorOverlay, overlayId } from './overlay'
// eslint-disable-next-line node/no-missing-import
import '@vite/env'
@@ -15,7 +9,7 @@ import '@vite/env'
declare const __BASE__: string
declare const __HMR_PROTOCOL__: string
declare const __HMR_HOSTNAME__: string
-declare const __HMR_PORT__: string | false
+declare const __HMR_PORT__: string
declare const __HMR_TIMEOUT__: number
declare const __HMR_ENABLE_OVERLAY__: boolean
@@ -24,12 +18,10 @@ console.log('[vite] connecting...')
// use server configuration, then fallback to inference
const socketProtocol =
__HMR_PROTOCOL__ || (location.protocol === 'https:' ? 'wss' : 'ws')
-const socketHost = __HMR_PORT__
- ? `${__HMR_HOSTNAME__ || location.hostname}:${__HMR_PORT__}`
- : `${__HMR_HOSTNAME__ || location.hostname}`
-
+const socketHost = `${__HMR_HOSTNAME__ || location.hostname}:${__HMR_PORT__}`
const socket = new WebSocket(`${socketProtocol}://${socketHost}`, 'vite-hmr')
const base = __BASE__ || '/'
+const messageBuffer: string[] = []
function warnFailedFetch(err: Error, path: string | string[]) {
if (!err.message.match('fetch')) {
@@ -59,9 +51,10 @@ async function handleMessage(payload: HMRPayload) {
switch (payload.type) {
case 'connected':
console.log(`[vite] connected.`)
+ sendMessageBuffer()
// proxy(nginx, docker) hmr ws maybe caused timeout,
// so send ping package let ws keep alive.
- setInterval(() => socket.send('ping'), __HMR_TIMEOUT__)
+ setInterval(() => socket.send('{"type":"ping"}'), __HMR_TIMEOUT__)
break
case 'update':
notifyListeners('vite:beforeUpdate', payload)
@@ -101,7 +94,7 @@ async function handleMessage(payload: HMRPayload) {
})
break
case 'custom': {
- notifyListeners(payload.event as CustomEventName
, payload.data)
+ notifyListeners(payload.event, payload.data)
break
}
case 'full-reload':
@@ -154,19 +147,9 @@ async function handleMessage(payload: HMRPayload) {
}
}
-function notifyListeners(
- event: 'vite:beforeUpdate',
- payload: UpdatePayload
-): void
-function notifyListeners(event: 'vite:beforePrune', payload: PrunePayload): void
-function notifyListeners(
- event: 'vite:beforeFullReload',
- payload: FullReloadPayload
-): void
-function notifyListeners(event: 'vite:error', payload: ErrorPayload): void
function notifyListeners(
- event: CustomEventName,
- data: any
+ event: T,
+ data: InferCustomEventPayload
): void
function notifyListeners(event: string, data: any): void {
const cbs = customListenersMap.get(event)
@@ -361,6 +344,13 @@ async function fetchUpdate({ path, acceptedPath, timestamp }: Update) {
}
}
+function sendMessageBuffer() {
+ if (socket.readyState === 1) {
+ messageBuffer.forEach((msg) => socket.send(msg))
+ messageBuffer.length = 0
+ }
+}
+
interface HotModule {
id: string
callbacks: HotCallback[]
@@ -382,9 +372,7 @@ const ctxToListenersMap = new Map<
Map void)[]>
>()
-// Just infer the return type for now
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-export const createHotContext = (ownerPath: string) => {
+export function createHotContext(ownerPath: string): ViteHotContext {
if (!dataMap.has(ownerPath)) {
dataMap.set(ownerPath, {})
}
@@ -425,12 +413,12 @@ export const createHotContext = (ownerPath: string) => {
hotModulesMap.set(ownerPath, mod)
}
- const hot = {
+ const hot: ViteHotContext = {
get data() {
return dataMap.get(ownerPath)
},
- accept(deps: any, callback?: any) {
+ accept(deps?: any, callback?: any) {
if (typeof deps === 'function' || !deps) {
// self-accept: hot.accept(() => {})
acceptDeps([ownerPath], ([mod]) => deps && deps(mod))
@@ -451,10 +439,11 @@ export const createHotContext = (ownerPath: string) => {
)
},
- dispose(cb: (data: any) => void) {
+ dispose(cb) {
disposeMap.set(ownerPath, cb)
},
+ // @ts-expect-error untyped
prune(cb: (data: any) => void) {
pruneMap.set(ownerPath, cb)
},
@@ -470,7 +459,7 @@ export const createHotContext = (ownerPath: string) => {
},
// custom events
- on: (event: string, cb: (data: any) => void) => {
+ on(event, cb) {
const addToMap = (map: Map) => {
const existing = map.get(event) || []
existing.push(cb)
@@ -478,6 +467,11 @@ export const createHotContext = (ownerPath: string) => {
}
addToMap(customListenersMap)
addToMap(newListeners)
+ },
+
+ send(event, data) {
+ messageBuffer.push(JSON.stringify({ type: 'custom', event, data }))
+ sendMessageBuffer()
}
}
diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts
index 021fd6d6f4baef..ff03352a20d7a7 100644
--- a/packages/vite/src/node/build.ts
+++ b/packages/vite/src/node/build.ts
@@ -19,7 +19,6 @@ import type {
} from 'rollup'
import type Rollup from 'rollup'
import { buildReporterPlugin } from './plugins/reporter'
-import { buildHtmlPlugin } from './plugins/html'
import { buildEsbuildPlugin } from './plugins/esbuild'
import { terserPlugin } from './plugins/terser'
import type { Terser } from 'types/terser'
@@ -307,11 +306,11 @@ export function resolveBuildPlugins(config: ResolvedConfig): {
post: Plugin[]
} {
const options = config.build
+
return {
pre: [
...(options.watch ? [ensureWatchPlugin()] : []),
watchPackageDataPlugin(config),
- buildHtmlPlugin(config),
commonjsPlugin(options.commonjsOptions),
dataURIPlugin(),
dynamicImportVars(options.dynamicImportVarsOptions),
@@ -322,7 +321,7 @@ export function resolveBuildPlugins(config: ResolvedConfig): {
],
post: [
buildImportAnalysisPlugin(config),
- buildEsbuildPlugin(config),
+ ...(config.esbuild !== false ? [buildEsbuildPlugin(config)] : []),
...(options.minify ? [terserPlugin(config)] : []),
...(options.manifest ? [manifestPlugin(config)] : []),
...(options.ssrManifest ? [ssrManifestPlugin(config)] : []),
diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts
index 68fe8abe85fc6d..9910cbb3a8b004 100644
--- a/packages/vite/src/node/config.ts
+++ b/packages/vite/src/node/config.ts
@@ -248,6 +248,7 @@ export type ResolvedConfig = Readonly<
cacheDir: string
command: 'build' | 'serve'
mode: string
+ isWorker: boolean
isProduction: boolean
env: Record
resolve: ResolveOptions & {
@@ -476,6 +477,7 @@ export async function resolveConfig(
cacheDir,
command,
mode,
+ isWorker: false,
isProduction,
plugins: userPlugins,
server,
@@ -508,7 +510,7 @@ export async function resolveConfig(
// flat config.worker.plugin
const [workerPrePlugins, workerNormalPlugins, workerPostPlugins] =
sortUserPlugins(config.worker?.plugins as Plugin[])
- const workerResolved = { ...resolved }
+ const workerResolved: ResolvedConfig = { ...resolved, isWorker: true }
resolved.worker.plugins = await resolvePlugins(
workerResolved,
workerPrePlugins,
diff --git a/packages/vite/src/node/constants.ts b/packages/vite/src/node/constants.ts
index 9612cd8c96460d..1741bf2dd7a94b 100644
--- a/packages/vite/src/node/constants.ts
+++ b/packages/vite/src/node/constants.ts
@@ -6,6 +6,21 @@ export const DEFAULT_MAIN_FIELDS = [
'jsnext'
]
+/**
+ * A non-exhaustive list of known-to-be-ES-module entry names.
+ * From
+ */
+export const KNOWN_ESM_MAIN_FIELDS = [
+ 'module',
+ 'jsnext:main',
+ 'jsnext',
+ 'esnext',
+ 'es2015',
+ 'es2020',
+ 'fesm2015',
+ 'fesm2020'
+]
+
export const DEFAULT_EXTENSIONS = [
'.mjs',
'.js',
diff --git a/packages/vite/src/node/importGlob.ts b/packages/vite/src/node/importGlob.ts
index 8ed3ba66d09744..a759bee2b5fa59 100644
--- a/packages/vite/src/node/importGlob.ts
+++ b/packages/vite/src/node/importGlob.ts
@@ -147,7 +147,7 @@ export async function transformImportGlob(
)
}
entries += ` ${JSON.stringify(file)}: ${JSON.stringify(
- await fsp.readFile(path.join(base, file), 'utf-8')
+ await fsp.readFile(path.join(base, files[i]), 'utf-8')
)},`
} else {
const importeeUrl = isCSSRequest(importee) ? `${importee}?used` : importee
diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts
index f0f217c9be03d3..2e849d846527ca 100644
--- a/packages/vite/src/node/index.ts
+++ b/packages/vite/src/node/index.ts
@@ -40,7 +40,8 @@ export type {
DepOptimizationOptions,
DepOptimizationResult,
DepOptimizationProcessing,
- OptimizedDepInfo
+ OptimizedDepInfo,
+ OptimizedDeps
} from './optimizer'
export type { Plugin } from './plugin'
export type { PackageCache, PackageData } from './packages'
@@ -72,7 +73,11 @@ export type { TransformOptions as EsbuildTransformOptions } from 'esbuild'
export type { ESBuildOptions, ESBuildTransformResult } from './plugins/esbuild'
export type { Manifest, ManifestChunk } from './plugins/manifest'
export type { ResolveOptions, InternalResolveOptions } from './plugins/resolve'
-export type { WebSocketServer } from './server/ws'
+export type {
+ WebSocketServer,
+ WebSocketClient,
+ WebSocketCustomListener
+} from './server/ws'
export type { PluginContainer } from './server/pluginContainer'
export type { ModuleGraph, ModuleNode, ResolvedUrl } from './server/moduleGraph'
export type { SendOptions } from './server/send'
@@ -103,6 +108,7 @@ export type {
export type { Terser } from 'types/terser'
export type { RollupCommonJSOptions } from 'types/commonjs'
export type { RollupDynamicImportVarsOptions } from 'types/dynamicImportVars'
+export type { CustomEventMap, InferCustomEventPayload } from 'types/customEvent'
export type { Matcher, AnymatchPattern, AnymatchFn } from 'types/anymatch'
export type { SplitVendorChunkCache } from './plugins/splitVendorChunk'
diff --git a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts
index 3ff86c213a54a2..4303be0ec876e7 100644
--- a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts
+++ b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts
@@ -37,8 +37,7 @@ const externalTypes = [
export function esbuildDepPlugin(
qualified: Record,
exportsData: Record,
- config: ResolvedConfig,
- ssr?: boolean
+ config: ResolvedConfig
): Plugin {
// remove optimizable extensions from `externalTypes` list
const allExternalTypes = config.optimizeDeps.extensions
@@ -48,12 +47,13 @@ export function esbuildDepPlugin(
: externalTypes
// default resolver which prefers ESM
- const _resolve = config.createResolver({ asSrc: false })
+ const _resolve = config.createResolver({ asSrc: false, scan: true })
// cjs resolver that prefers Node
const _resolveRequire = config.createResolver({
asSrc: false,
- isRequire: true
+ isRequire: true,
+ scan: true
})
const resolve = (
@@ -72,7 +72,7 @@ export function esbuildDepPlugin(
_importer = importer in qualified ? qualified[importer] : importer
}
const resolver = kind.startsWith('require') ? _resolveRequire : _resolve
- return resolver(id, _importer, undefined, ssr)
+ return resolver(id, _importer, undefined)
}
return {
diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts
index 2bdd54dc3a899a..88c41801938b98 100644
--- a/packages/vite/src/node/optimizer/index.ts
+++ b/packages/vite/src/node/optimizer/index.ts
@@ -21,7 +21,8 @@ import { scanImports } from './scan'
import { transformWithEsbuild } from '../plugins/esbuild'
import { performance } from 'perf_hooks'
-const debug = createDebugger('vite:deps')
+export const debuggerViteDeps = createDebugger('vite:deps')
+const debug = debuggerViteDeps
const isDebugEnabled = _debug('vite:deps').enabled
const jsExtensionRE = /\.js$/i
@@ -33,6 +34,12 @@ export type ExportsData = ReturnType & {
hasReExports?: true
}
+export interface OptimizedDeps {
+ metadata: DepOptimizationMetadata
+ scanProcessing?: Promise
+ registerMissingImport: (id: string, resolved: string) => OptimizedDepInfo
+}
+
export interface DepOptimizationOptions {
/**
* By default, Vite will crawl your `index.html` to detect dependencies that
@@ -97,17 +104,11 @@ export interface DepOptimizationOptions {
}
export interface DepOptimizationResult {
- /**
- * After a re-optimization, the internal bundled chunks may change
- * and a full page reload is required if that is the case
- * If the files are stable, we can avoid the reload that is expensive
- * for large applications
- */
- alteredFiles: boolean
+ metadata: DepOptimizationMetadata
/**
* When doing a re-run, if there are newly discovered dependendencies
- * the page reload will be delayed until the next rerun so the
- * result will be discarded
+ * the page reload will be delayed until the next rerun so we need
+ * to be able to discard the result
*/
commit: () => void
cancel: () => void
@@ -119,8 +120,9 @@ export interface DepOptimizationProcessing {
}
export interface OptimizedDepInfo {
+ id: string
file: string
- src: string
+ src?: string
needsInterop?: boolean
browserHash?: string
fileHash?: string
@@ -155,6 +157,10 @@ export interface DepOptimizationMetadata {
* Metadata for each newly discovered dependency after processing
*/
discovered: Record
+ /**
+ * OptimizedDepInfo list
+ */
+ depInfoList: OptimizedDepInfo[]
}
/**
@@ -163,45 +169,65 @@ export interface DepOptimizationMetadata {
export async function optimizeDeps(
config: ResolvedConfig,
force = config.server.force,
- asCommand = false,
- newDeps?: Record, // missing imports encountered after server has started
- ssr?: boolean
+ asCommand = false
): Promise {
- const { metadata, run } = await createOptimizeDepsRun(
+ const log = asCommand ? config.logger.info : debug
+
+ const cachedMetadata = loadCachedDepOptimizationMetadata(
config,
force,
- asCommand,
- null,
- newDeps,
- ssr
+ asCommand
)
- const result = await run()
+ if (cachedMetadata) {
+ return cachedMetadata
+ }
+ const depsInfo = await discoverProjectDependencies(config)
+
+ const depsString = depsLogString(Object.keys(depsInfo))
+ log(colors.green(`Optimizing dependencies:\n ${depsString}`))
+
+ const result = await runOptimizeDeps(config, depsInfo)
+
result.commit()
- return metadata
+
+ return result.metadata
+}
+
+export function createOptimizedDepsMetadata(
+ config: ResolvedConfig,
+ timestamp?: string
+): DepOptimizationMetadata {
+ const hash = getDepHash(config)
+ return {
+ hash,
+ browserHash: getOptimizedBrowserHash(hash, {}, timestamp),
+ optimized: {},
+ chunks: {},
+ discovered: {},
+ depInfoList: []
+ }
+}
+
+export function addOptimizedDepInfo(
+ metadata: DepOptimizationMetadata,
+ type: 'optimized' | 'discovered' | 'chunks',
+ depInfo: OptimizedDepInfo
+): OptimizedDepInfo {
+ metadata[type][depInfo.id] = depInfo
+ metadata.depInfoList.push(depInfo)
+ return depInfo
}
/**
- * Internally, Vite uses this function to prepare a optimizeDeps run. When Vite starts, we can get
- * the metadata and start the server without waiting for the optimizeDeps processing to be completed
+ * Creates the initial dep optimization metadata, loading it from the deps cache
+ * if it exists and pre-bundling isn't forced
*/
-export async function createOptimizeDepsRun(
+export function loadCachedDepOptimizationMetadata(
config: ResolvedConfig,
force = config.server.force,
- asCommand = false,
- currentData: DepOptimizationMetadata | null = null,
- newDeps?: Record, // missing imports encountered after server has started
- ssr?: boolean
-): Promise<{
- metadata: DepOptimizationMetadata
- run: () => Promise
-}> {
- config = {
- ...config,
- command: 'build'
- }
-
- const { root, logger } = config
- const log = asCommand ? logger.info : debug
+ asCommand = false
+): DepOptimizationMetadata | undefined {
+ const log = asCommand ? config.logger.info : debug
// Before Vite 2.9, dependencies were cached in the root of the cacheDir
// For compat, we remove the cache if we find the old structure
@@ -210,49 +236,105 @@ export async function createOptimizeDepsRun(
}
const depsCacheDir = getDepsCacheDir(config)
- const processingCacheDir = getProcessingDepsCacheDir(config)
-
- const mainHash = getDepHash(root, config)
-
- const processing = newDepOptimizationProcessing()
-
- const metadata: DepOptimizationMetadata = {
- hash: mainHash,
- browserHash: mainHash,
- optimized: {},
- chunks: {},
- discovered: {}
- }
if (!force) {
- let prevData: DepOptimizationMetadata | undefined
+ let cachedMetadata: DepOptimizationMetadata | undefined
try {
- const prevDataPath = path.join(depsCacheDir, '_metadata.json')
- prevData = parseOptimizedDepsMetadata(
- fs.readFileSync(prevDataPath, 'utf-8'),
+ const cachedMetadataPath = path.join(depsCacheDir, '_metadata.json')
+ cachedMetadata = parseOptimizedDepsMetadata(
+ fs.readFileSync(cachedMetadataPath, 'utf-8'),
depsCacheDir
)
} catch (e) {}
// hash is consistent, no need to re-bundle
- if (prevData && prevData.hash === metadata.hash) {
+ if (cachedMetadata && cachedMetadata.hash === getDepHash(config)) {
log('Hash is consistent. Skipping. Use --force to override.')
// Nothing to commit or cancel as we are using the cache, we only
// need to resolve the processing promise so requests can move on
- const resolve = () => {
- processing.resolve()
- }
- return {
- metadata: prevData,
- run: async () => {
- return {
- alteredFiles: false,
- commit: resolve,
- cancel: resolve
- }
- }
- }
+ return cachedMetadata
+ }
+ } else {
+ config.logger.info('Forced re-optimization of dependencies')
+ }
+
+ // Start with a fresh cache
+ removeDirSync(depsCacheDir)
+}
+
+/**
+ * Initial optimizeDeps at server start. Perform a fast scan using esbuild to
+ * find deps to pre-bundle and include user hard-coded dependencies
+ */
+export async function discoverProjectDependencies(
+ config: ResolvedConfig,
+ timestamp?: string
+): Promise> {
+ const { deps, missing } = await scanImports(config)
+
+ const missingIds = Object.keys(missing)
+ if (missingIds.length) {
+ throw new Error(
+ `The following dependencies are imported but could not be resolved:\n\n ${missingIds
+ .map(
+ (id) =>
+ `${colors.cyan(id)} ${colors.white(
+ colors.dim(`(imported by ${missing[id]})`)
+ )}`
+ )
+ .join(`\n `)}\n\nAre they installed?`
+ )
+ }
+
+ await addManuallyIncludedOptimizeDeps(deps, config)
+
+ const browserHash = getOptimizedBrowserHash(
+ getDepHash(config),
+ deps,
+ timestamp
+ )
+ const discovered: Record = {}
+ for (const id in deps) {
+ const entry = deps[id]
+ discovered[id] = {
+ id,
+ file: getOptimizedDepPath(id, config),
+ src: entry,
+ browserHash: browserHash
}
}
+ return discovered
+}
+
+export function depsLogString(qualifiedIds: string[]): string {
+ if (isDebugEnabled) {
+ return colors.yellow(qualifiedIds.join(`\n `))
+ } else {
+ const total = qualifiedIds.length
+ const maxListed = 5
+ const listed = Math.min(total, maxListed)
+ const extra = Math.max(0, total - maxListed)
+ return colors.yellow(
+ qualifiedIds.slice(0, listed).join(`, `) +
+ (extra > 0 ? `, ...and ${extra} more` : ``)
+ )
+ }
+}
+
+/**
+ * Internally, Vite uses this function to prepare a optimizeDeps run. When Vite starts, we can get
+ * the metadata and start the server without waiting for the optimizeDeps processing to be completed
+ */
+export async function runOptimizeDeps(
+ config: ResolvedConfig,
+ depsInfo: Record
+): Promise {
+ config = {
+ ...config,
+ command: 'build'
+ }
+
+ const depsCacheDir = getDepsCacheDir(config)
+ const processingCacheDir = getProcessingDepsCacheDir(config)
// Create a temporal directory so we don't need to delete optimized deps
// until they have been processed. This also avoids leaving the deps cache
@@ -270,319 +352,190 @@ export async function createOptimizeDepsRun(
JSON.stringify({ type: 'module' })
)
- let newBrowserHash: string
-
- let deps: Record
- if (!newDeps) {
- // Initial optimizeDeps at server start. Perform a fast scan using esbuild to
- // find deps to pre-bundle and include user hard-coded dependencies
-
- let missing: Record
- ;({ deps, missing } = await scanImports(config))
-
- const missingIds = Object.keys(missing)
- if (missingIds.length) {
- processing.resolve()
- throw new Error(
- `The following dependencies are imported but could not be resolved:\n\n ${missingIds
- .map(
- (id) =>
- `${colors.cyan(id)} ${colors.white(
- colors.dim(`(imported by ${missing[id]})`)
- )}`
- )
- .join(`\n `)}\n\nAre they installed?`
- )
- }
-
- try {
- await addManuallyIncludedOptimizeDeps(deps, config)
- } catch (e) {
- processing.resolve()
- throw e
- }
+ const metadata = createOptimizedDepsMetadata(config)
- // update browser hash
- newBrowserHash = metadata.browserHash = getOptimizedBrowserHash(
- metadata.hash,
- deps
- )
-
- // We generate the mapping of dependency ids to their cache file location
- // before processing the dependencies with esbuild. This allow us to continue
- // processing files in the importAnalysis and resolve plugins
- for (const id in deps) {
- const entry = deps[id]
- metadata.optimized[id] = {
- file: getOptimizedDepPath(id, config),
- src: entry,
- browserHash: newBrowserHash,
- processing: processing.promise
- }
- }
- } else {
- // Missing dependencies were found at run-time, optimizeDeps called while the
- // server is running
- deps = depsFromOptimizedDepInfo(newDeps)
+ metadata.browserHash = getOptimizedBrowserHash(
+ metadata.hash,
+ depsFromOptimizedDepInfo(depsInfo)
+ )
- metadata.optimized = newDeps
+ // We prebundle dependencies with esbuild and cache them, but there is no need
+ // to wait here. Code that needs to access the cached deps needs to await
+ // the optimizedDepInfo.processing promise for each dep
- // For reruns keep current global browser hash and newDeps individual hashes until we know
- // if files are stable so we can avoid a full page reload
- metadata.browserHash = currentData!.browserHash
- newBrowserHash = getOptimizedBrowserHash(metadata.hash, deps)
- }
+ const qualifiedIds = Object.keys(depsInfo)
- return { metadata, run: prebundleDeps }
-
- async function prebundleDeps(): Promise {
- // We prebundle dependencies with esbuild and cache them, but there is no need
- // to wait here. Code that needs to access the cached deps needs to await
- // the optimizeDepInfo.processing promise for each dep
-
- const qualifiedIds = Object.keys(deps)
-
- if (!qualifiedIds.length) {
- return {
- alteredFiles: false,
- commit() {
- // Write metadata file, delete `deps` folder and rename the `processing` folder to `deps`
- commitProcessingDepsCacheSync()
- log(`No dependencies to bundle. Skipping.\n\n\n`)
- processing.resolve()
- },
- cancel
- }
+ if (!qualifiedIds.length) {
+ return {
+ metadata,
+ commit() {
+ // Write metadata file, delete `deps` folder and rename the `processing` folder to `deps`
+ commitProcessingDepsCacheSync()
+ },
+ cancel
}
+ }
- let depsString: string
- if (isDebugEnabled) {
- depsString = colors.yellow(qualifiedIds.join(`\n `))
+ // esbuild generates nested directory output with lowest common ancestor base
+ // this is unpredictable and makes it difficult to analyze entry / output
+ // mapping. So what we do here is:
+ // 1. flatten all ids to eliminate slash
+ // 2. in the plugin, read the entry ourselves as virtual files to retain the
+ // path.
+ const flatIdDeps: Record = {}
+ const idToExports: Record = {}
+ const flatIdToExports: Record = {}
+
+ const { plugins = [], ...esbuildOptions } =
+ config.optimizeDeps?.esbuildOptions ?? {}
+
+ await init
+ for (const id in depsInfo) {
+ const flatId = flattenId(id)
+ const filePath = (flatIdDeps[flatId] = depsInfo[id].src!)
+ let exportsData: ExportsData
+ if (config.optimizeDeps.extensions?.some((ext) => filePath.endsWith(ext))) {
+ // For custom supported extensions, build the entry file to transform it into JS,
+ // and then parse with es-module-lexer. Note that the `bundle` option is not `true`,
+ // so only the entry file is being transformed.
+ const result = await build({
+ ...esbuildOptions,
+ plugins,
+ entryPoints: [filePath],
+ write: false,
+ format: 'esm'
+ })
+ exportsData = parse(result.outputFiles[0].text) as ExportsData
} else {
- const total = qualifiedIds.length
- const maxListed = 5
- const listed = Math.min(total, maxListed)
- const extra = Math.max(0, total - maxListed)
- depsString = colors.yellow(
- qualifiedIds.slice(0, listed).join(`\n `) +
- (extra > 0 ? `\n (...and ${extra} more)` : ``)
- )
- }
-
- if (!asCommand) {
- if (!newDeps) {
- // This is auto run on server start - let the user know that we are
- // pre-optimizing deps
- logger.info(colors.green(`Pre-bundling dependencies:\n ${depsString}`))
- logger.info(
- `(this will be run only when your dependencies or config have changed)`
+ const entryContent = fs.readFileSync(filePath, 'utf-8')
+ try {
+ exportsData = parse(entryContent) as ExportsData
+ } catch {
+ debug(
+ `Unable to parse dependency: ${id}. Trying again with a JSX transform.`
)
- }
- } else {
- logger.info(colors.green(`Optimizing dependencies:\n ${depsString}`))
- }
-
- // esbuild generates nested directory output with lowest common ancestor base
- // this is unpredictable and makes it difficult to analyze entry / output
- // mapping. So what we do here is:
- // 1. flatten all ids to eliminate slash
- // 2. in the plugin, read the entry ourselves as virtual files to retain the
- // path.
- const flatIdDeps: Record = {}
- const idToExports: Record = {}
- const flatIdToExports: Record = {}
-
- const { plugins = [], ...esbuildOptions } =
- config.optimizeDeps?.esbuildOptions ?? {}
-
- await init
- for (const id in deps) {
- const flatId = flattenId(id)
- const filePath = (flatIdDeps[flatId] = deps[id])
- let exportsData: ExportsData
- if (
- config.optimizeDeps.extensions?.some((ext) => filePath.endsWith(ext))
- ) {
- // For custom supported extensions, build the entry file to transform it into JS,
- // and then parse with es-module-lexer. Note that the `bundle` option is not `true`,
- // so only the entry file is being transformed.
- const result = await build({
- ...esbuildOptions,
- plugins,
- entryPoints: [filePath],
- write: false,
- format: 'esm'
+ const transformed = await transformWithEsbuild(entryContent, filePath, {
+ loader: 'jsx'
})
- exportsData = parse(result.outputFiles[0].text) as ExportsData
- } else {
- const entryContent = fs.readFileSync(filePath, 'utf-8')
- try {
- exportsData = parse(entryContent) as ExportsData
- } catch {
- debug(
- `Unable to parse dependency: ${id}. Trying again with a JSX transform.`
- )
- const transformed = await transformWithEsbuild(
- entryContent,
- filePath,
- {
- loader: 'jsx'
- }
- )
- // Ensure that optimization won't fail by defaulting '.js' to the JSX parser.
- // This is useful for packages such as Gatsby.
- esbuildOptions.loader = {
- '.js': 'jsx',
- ...esbuildOptions.loader
- }
- exportsData = parse(transformed.code) as ExportsData
+ // Ensure that optimization won't fail by defaulting '.js' to the JSX parser.
+ // This is useful for packages such as Gatsby.
+ esbuildOptions.loader = {
+ '.js': 'jsx',
+ ...esbuildOptions.loader
}
- for (const { ss, se } of exportsData[0]) {
- const exp = entryContent.slice(ss, se)
- if (/export\s+\*\s+from/.test(exp)) {
- exportsData.hasReExports = true
- }
+ exportsData = parse(transformed.code) as ExportsData
+ }
+ for (const { ss, se } of exportsData[0]) {
+ const exp = entryContent.slice(ss, se)
+ if (/export\s+\*\s+from/.test(exp)) {
+ exportsData.hasReExports = true
}
}
-
- idToExports[id] = exportsData
- flatIdToExports[flatId] = exportsData
}
- const define: Record = {
- 'process.env.NODE_ENV': JSON.stringify(config.mode)
- }
- for (const key in config.define) {
- const value = config.define[key]
- define[key] = typeof value === 'string' ? value : JSON.stringify(value)
- }
+ idToExports[id] = exportsData
+ flatIdToExports[flatId] = exportsData
+ }
- const start = performance.now()
-
- const result = await build({
- absWorkingDir: process.cwd(),
- entryPoints: Object.keys(flatIdDeps),
- bundle: true,
- format: 'esm',
- target: config.build.target || undefined,
- external: config.optimizeDeps?.exclude,
- logLevel: 'error',
- splitting: true,
- sourcemap: true,
- outdir: processingCacheDir,
- ignoreAnnotations: true,
- metafile: true,
- define,
- plugins: [
- ...plugins,
- esbuildDepPlugin(flatIdDeps, flatIdToExports, config, ssr)
- ],
- ...esbuildOptions
- })
+ const define: Record = {
+ 'process.env.NODE_ENV': JSON.stringify(config.mode)
+ }
+ for (const key in config.define) {
+ const value = config.define[key]
+ define[key] = typeof value === 'string' ? value : JSON.stringify(value)
+ }
- const meta = result.metafile!
+ const start = performance.now()
+
+ const result = await build({
+ absWorkingDir: process.cwd(),
+ entryPoints: Object.keys(flatIdDeps),
+ bundle: true,
+ format: 'esm',
+ target: config.build.target || undefined,
+ external: config.optimizeDeps?.exclude,
+ logLevel: 'error',
+ splitting: true,
+ sourcemap: true,
+ outdir: processingCacheDir,
+ ignoreAnnotations: true,
+ metafile: true,
+ define,
+ plugins: [
+ ...plugins,
+ esbuildDepPlugin(flatIdDeps, flatIdToExports, config)
+ ],
+ ...esbuildOptions
+ })
- // the paths in `meta.outputs` are relative to `process.cwd()`
- const processingCacheDirOutputPath = path.relative(
- process.cwd(),
- processingCacheDir
- )
+ const meta = result.metafile!
- for (const id in deps) {
- const optimizedInfo = metadata.optimized[id]
- optimizedInfo.needsInterop = needsInterop(
- id,
- idToExports[id],
- meta.outputs,
- processingCacheDirOutputPath
- )
- const output =
- meta.outputs[
- path.relative(process.cwd(), getProcessingDepPath(id, config))
- ]
- if (output) {
- // We only need to hash the output.imports in to check for stability, but adding the hash
- // and file path gives us a unique hash that may be useful for other things in the future
- optimizedInfo.fileHash = getHash(
- metadata.hash + optimizedInfo.file + JSON.stringify(output.imports)
- )
- }
- }
+ // the paths in `meta.outputs` are relative to `process.cwd()`
+ const processingCacheDirOutputPath = path.relative(
+ process.cwd(),
+ processingCacheDir
+ )
- // This only runs when missing deps are processed. Previous optimized deps are stable if
- // the newly discovered deps don't have common chunks with them. Comparing their fileHash we
- // can find out if it is safe to keep the current browser state. If one of the file hashes
- // changed, a full page reload is needed
- let alteredFiles = false
- if (currentData) {
- alteredFiles = Object.keys(currentData.optimized).some((dep) => {
- const currentInfo = currentData.optimized[dep]
- const info = metadata.optimized[dep]
- return (
- !info?.fileHash ||
- !currentInfo?.fileHash ||
- info?.fileHash !== currentInfo?.fileHash
- )
- })
- debug(`optimized deps have altered files: ${alteredFiles}`)
- }
+ for (const id in depsInfo) {
+ const output = esbuildOutputFromId(meta.outputs, id, processingCacheDir)
+
+ addOptimizedDepInfo(metadata, 'optimized', {
+ ...depsInfo[id],
+ needsInterop: needsInterop(id, idToExports[id], output),
+ // We only need to hash the output.imports in to check for stability, but adding the hash
+ // and file path gives us a unique hash that may be useful for other things in the future
+ fileHash: getHash(
+ metadata.hash + depsInfo[id].file + JSON.stringify(output.imports)
+ ),
+ browserHash: metadata.browserHash
+ })
+ }
- for (const o of Object.keys(meta.outputs)) {
- if (!o.match(jsMapExtensionRE)) {
- const id = path
- .relative(processingCacheDirOutputPath, o)
- .replace(jsExtensionRE, '')
- const file = getOptimizedDepPath(id, config)
- if (!findFileInfo(metadata.optimized, file)) {
- metadata.chunks[id] = {
- file,
- src: '',
- needsInterop: false,
- browserHash:
- (!alteredFiles && currentData?.chunks[id]?.browserHash) ||
- newBrowserHash
- }
- }
+ for (const o of Object.keys(meta.outputs)) {
+ if (!o.match(jsMapExtensionRE)) {
+ const id = path
+ .relative(processingCacheDirOutputPath, o)
+ .replace(jsExtensionRE, '')
+ const file = getOptimizedDepPath(id, config)
+ if (
+ !findOptimizedDepInfoInRecord(
+ metadata.optimized,
+ (depInfo) => depInfo.file === file
+ )
+ ) {
+ addOptimizedDepInfo(metadata, 'chunks', {
+ id,
+ file,
+ needsInterop: false,
+ browserHash: metadata.browserHash
+ })
}
}
+ }
- if (alteredFiles) {
- metadata.browserHash = newBrowserHash
- }
+ const dataPath = path.join(processingCacheDir, '_metadata.json')
+ writeFile(dataPath, stringifyOptimizedDepsMetadata(metadata, depsCacheDir))
- debug(`deps bundled in ${(performance.now() - start).toFixed(2)}ms`)
+ debug(`deps bundled in ${(performance.now() - start).toFixed(2)}ms`)
- return {
- alteredFiles,
- commit() {
- if (alteredFiles) {
- // Overwrite individual hashes with the new global browserHash, a full page reload is required
- // New deps that ended up with a different hash replaced while doing analysis import are going to
- // return a not found so the browser doesn't cache them. And will properly get loaded after the reload
- for (const id in deps) {
- metadata.optimized[id].browserHash = newBrowserHash
- }
- }
- // Write metadata file, delete `deps` folder and rename the new `processing` folder to `deps` in sync
- commitProcessingDepsCacheSync()
- processing.resolve()
- },
- cancel
- }
+ return {
+ metadata,
+ commit() {
+ // Write metadata file, delete `deps` folder and rename the new `processing` folder to `deps` in sync
+ commitProcessingDepsCacheSync()
+ },
+ cancel
}
function commitProcessingDepsCacheSync() {
- // Rewire the file paths from the temporal processing dir to the final deps cache dir
- const dataPath = path.join(processingCacheDir, '_metadata.json')
- writeFile(dataPath, stringifyOptimizedDepsMetadata(metadata, depsCacheDir))
// Processing is done, we can now replace the depsCacheDir with processingCacheDir
+ // Rewire the file paths from the temporal processing dir to the final deps cache dir
removeDirSync(depsCacheDir)
fs.renameSync(processingCacheDir, depsCacheDir)
}
function cancel() {
removeDirSync(processingCacheDir)
- processing.resolve()
}
}
@@ -639,38 +592,20 @@ export function depsFromOptimizedDepInfo(
depsInfo: Record
) {
return Object.fromEntries(
- Object.entries(depsInfo).map((d) => [d[0], d[1].src])
+ Object.entries(depsInfo).map((d) => [d[0], d[1].src!])
)
}
-export function getHash(text: string) {
- return createHash('sha256').update(text).digest('hex').substring(0, 8)
-}
-
-function getOptimizedBrowserHash(hash: string, deps: Record) {
- return getHash(hash + JSON.stringify(deps))
-}
-
-function getCachedDepFilePath(id: string, depsCacheDir: string) {
- return normalizePath(path.resolve(depsCacheDir, flattenId(id) + '.js'))
-}
-
export function getOptimizedDepPath(id: string, config: ResolvedConfig) {
- return getCachedDepFilePath(id, getDepsCacheDir(config))
+ return normalizePath(
+ path.resolve(getDepsCacheDir(config), flattenId(id) + '.js')
+ )
}
export function getDepsCacheDir(config: ResolvedConfig) {
return normalizePath(path.resolve(config.cacheDir, 'deps'))
}
-function getProcessingDepFilePath(id: string, processingCacheDir: string) {
- return normalizePath(path.resolve(processingCacheDir, flattenId(id) + '.js'))
-}
-
-function getProcessingDepPath(id: string, config: ResolvedConfig) {
- return getProcessingDepFilePath(id, getProcessingDepsCacheDir(config))
-}
-
function getProcessingDepsCacheDir(config: ResolvedConfig) {
return normalizePath(path.resolve(config.cacheDir, 'processing'))
}
@@ -701,27 +636,48 @@ export function createIsOptimizedDepUrl(config: ResolvedConfig) {
function parseOptimizedDepsMetadata(
jsonMetadata: string,
depsCacheDir: string
-) {
- const metadata = JSON.parse(jsonMetadata, (key: string, value: string) => {
- // Paths can be absolute or relative to the deps cache dir where
- // the _metadata.json is located
- if (key === 'file' || key === 'src') {
- return normalizePath(path.resolve(depsCacheDir, value))
+): DepOptimizationMetadata | undefined {
+ const { hash, browserHash, optimized, chunks } = JSON.parse(
+ jsonMetadata,
+ (key: string, value: string) => {
+ // Paths can be absolute or relative to the deps cache dir where
+ // the _metadata.json is located
+ if (key === 'file' || key === 'src') {
+ return normalizePath(path.resolve(depsCacheDir, value))
+ }
+ return value
}
- return value
- })
- const { browserHash } = metadata
- for (const o of Object.keys(metadata.optimized)) {
- const depInfo = metadata.optimized[o]
- depInfo.browserHash = browserHash
+ )
+ if (
+ !chunks ||
+ Object.values(optimized).some((depInfo: any) => !depInfo.fileHash)
+ ) {
+ // outdated _metadata.json version, ignore
+ return
+ }
+ const metadata = {
+ hash,
+ browserHash,
+ optimized: {},
+ discovered: {},
+ chunks: {},
+ depInfoList: []
}
- metadata.chunks ||= {} // Support missing chunks for back compat
- for (const o of Object.keys(metadata.chunks)) {
- const depInfo = metadata.chunks[o]
- depInfo.src = ''
- depInfo.browserHash = browserHash
+ for (const id of Object.keys(optimized)) {
+ addOptimizedDepInfo(metadata, 'optimized', {
+ ...optimized[id],
+ id,
+ browserHash
+ })
+ }
+ for (const id of Object.keys(chunks)) {
+ addOptimizedDepInfo(metadata, 'chunks', {
+ ...chunks[id],
+ id,
+ browserHash,
+ needsInterop: false
+ })
}
- metadata.discovered = {}
return metadata
}
@@ -735,50 +691,53 @@ function stringifyOptimizedDepsMetadata(
metadata: DepOptimizationMetadata,
depsCacheDir: string
) {
+ const { hash, browserHash, optimized, chunks } = metadata
return JSON.stringify(
- metadata,
- (key: string, value: any) => {
- if (key === 'discovered' || key === 'processing') {
- return
- }
+ {
+ hash,
+ browserHash,
+ optimized: Object.fromEntries(
+ Object.values(optimized).map(
+ ({ id, src, file, fileHash, needsInterop }) => [
+ id,
+ {
+ src,
+ file,
+ fileHash,
+ needsInterop
+ }
+ ]
+ )
+ ),
+ chunks: Object.fromEntries(
+ Object.values(chunks).map(({ id, file }) => [id, { file }])
+ )
+ },
+ (key: string, value: string) => {
+ // Paths can be absolute or relative to the deps cache dir where
+ // the _metadata.json is located
if (key === 'file' || key === 'src') {
return normalizePath(path.relative(depsCacheDir, value))
}
- if (key === 'optimized') {
- // Only remove browserHash for individual dep info
- const cleaned: Record = {}
- for (const dep of Object.keys(value)) {
- const { browserHash, ...c } = value[dep]
- cleaned[dep] = c
- }
- return cleaned
- }
- if (key === 'optimized') {
- return Object.keys(value).reduce(
- (cleaned: Record, dep: string) => {
- const { browserHash, ...c } = value[dep]
- cleaned[dep] = c
- return cleaned
- },
- {}
- )
- }
- if (key === 'chunks') {
- return Object.keys(value).reduce(
- (cleaned: Record, dep: string) => {
- const { browserHash, needsInterop, src, ...c } = value[dep]
- cleaned[dep] = c
- return cleaned
- },
- {}
- )
- }
return value
},
2
)
}
+function esbuildOutputFromId(
+ outputs: Record,
+ id: string,
+ cacheDirOutputPath: string
+): any {
+ const flatId = flattenId(id) + '.js'
+ return outputs[
+ normalizePath(
+ path.relative(process.cwd(), path.join(cacheDirOutputPath, flatId))
+ )
+ ]
+}
+
// https://github.com/vitejs/vite/issues/1724#issuecomment-767619642
// a list of modules that pretends to be ESM but still uses `require`.
// this causes esbuild to wrap them as CJS even when its entry appears to be ESM.
@@ -787,8 +746,7 @@ const KNOWN_INTEROP_IDS = new Set(['moment'])
function needsInterop(
id: string,
exportsData: ExportsData,
- outputs: Record,
- cacheDirOutputPath: string
+ output: { exports: string[] }
): boolean {
if (KNOWN_INTEROP_IDS.has(id)) {
return true
@@ -802,17 +760,7 @@ function needsInterop(
// if a peer dependency used require() on a ESM dependency, esbuild turns the
// ESM dependency's entry chunk into a single default export... detect
// such cases by checking exports mismatch, and force interop.
- const flatId = flattenId(id) + '.js'
- let generatedExports: string[] | undefined
- for (const output in outputs) {
- if (
- normalizePath(output) ===
- normalizePath(path.join(cacheDirOutputPath, flatId))
- ) {
- generatedExports = outputs[output].exports
- break
- }
- }
+ const generatedExports: string[] = output.exports
if (
!generatedExports ||
@@ -829,8 +777,8 @@ function isSingleDefaultExport(exports: readonly string[]) {
const lockfileFormats = ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml']
-function getDepHash(root: string, config: ResolvedConfig): string {
- let content = lookupFile(root, lockfileFormats) || ''
+export function getDepHash(config: ResolvedConfig): string {
+ let content = lookupFile(config.root, lockfileFormats) || ''
// also take config into account
// only a subset of config options that can affect dep optimization
content += JSON.stringify(
@@ -860,27 +808,44 @@ function getDepHash(root: string, config: ResolvedConfig): string {
return value
}
)
- return createHash('sha256').update(content).digest('hex').substring(0, 8)
+ return getHash(content)
}
-export function optimizeDepInfoFromFile(
+function getOptimizedBrowserHash(
+ hash: string,
+ deps: Record,
+ timestamp = ''
+) {
+ return getHash(hash + JSON.stringify(deps) + timestamp)
+}
+
+export function getHash(text: string): string {
+ return createHash('sha256').update(text).digest('hex').substring(0, 8)
+}
+
+export function optimizedDepInfoFromId(
metadata: DepOptimizationMetadata,
- file: string
+ id: string
): OptimizedDepInfo | undefined {
return (
- findFileInfo(metadata.optimized, file) ||
- findFileInfo(metadata.discovered, file) ||
- findFileInfo(metadata.chunks, file)
+ metadata.optimized[id] || metadata.discovered[id] || metadata.chunks[id]
)
}
-function findFileInfo(
- dependenciesInfo: Record,
+export function optimizedDepInfoFromFile(
+ metadata: DepOptimizationMetadata,
file: string
+): OptimizedDepInfo | undefined {
+ return metadata.depInfoList.find((depInfo) => depInfo.file === file)
+}
+
+function findOptimizedDepInfoInRecord(
+ dependenciesInfo: Record,
+ callbackFn: (depInfo: OptimizedDepInfo, id: string) => any
): OptimizedDepInfo | undefined {
for (const o of Object.keys(dependenciesInfo)) {
const info = dependenciesInfo[o]
- if (info.file === file) {
+ if (callbackFn(info, o)) {
return info
}
}
@@ -890,7 +855,7 @@ export async function optimizedDepNeedsInterop(
metadata: DepOptimizationMetadata,
file: string
): Promise {
- const depInfo = optimizeDepInfoFromFile(metadata, file)
+ const depInfo = optimizedDepInfoFromFile(metadata, file)
if (!depInfo) return undefined
diff --git a/packages/vite/src/node/optimizer/registerMissing.ts b/packages/vite/src/node/optimizer/registerMissing.ts
index 256098f351e2e8..ee4824389c202b 100644
--- a/packages/vite/src/node/optimizer/registerMissing.ts
+++ b/packages/vite/src/node/optimizer/registerMissing.ts
@@ -1,18 +1,26 @@
import colors from 'picocolors'
+import _debug from 'debug'
import {
- createOptimizeDepsRun,
+ runOptimizeDeps,
getOptimizedDepPath,
getHash,
depsFromOptimizedDepInfo,
- newDepOptimizationProcessing
+ newDepOptimizationProcessing,
+ loadCachedDepOptimizationMetadata,
+ createOptimizedDepsMetadata,
+ addOptimizedDepInfo,
+ discoverProjectDependencies,
+ depsLogString,
+ debuggerViteDeps as debug
} from '.'
import type {
- DepOptimizationMetadata,
DepOptimizationProcessing,
- OptimizedDepInfo
+ OptimizedDepInfo,
+ OptimizedDeps
} from '.'
import type { ViteDevServer } from '..'
-import { resolveSSRExternal } from '../ssr/ssrExternal'
+
+const isDebugEnabled = _debug('vite:deps').enabled
/**
* The amount to wait for requests to register newly found dependencies before triggering
@@ -20,16 +28,39 @@ import { resolveSSRExternal } from '../ssr/ssrExternal'
*/
const debounceMs = 100
-export function createMissingImporterRegisterFn(
- server: ViteDevServer,
- initialProcessingPromise: Promise
-): (id: string, resolved: string, ssr?: boolean) => OptimizedDepInfo {
- const { logger } = server.config
- let metadata = server._optimizeDepsMetadata!
+export function createOptimizedDeps(server: ViteDevServer): OptimizedDeps {
+ const { config } = server
+ const { logger } = config
+
+ const sessionTimestamp = Date.now().toString()
+
+ const cachedMetadata = loadCachedDepOptimizationMetadata(config)
+
+ const optimizedDeps: OptimizedDeps = {
+ metadata:
+ cachedMetadata || createOptimizedDepsMetadata(config, sessionTimestamp),
+ registerMissingImport
+ }
let handle: NodeJS.Timeout | undefined
let newDepsDiscovered = false
+ let newDepsToLog: string[] = []
+ let newDepsToLogHandle: NodeJS.Timeout | undefined
+ const logNewlyDiscoveredDeps = () => {
+ if (newDepsToLog.length) {
+ config.logger.info(
+ colors.green(
+ `✨ new dependencies optimized: ${depsLogString(newDepsToLog)}`
+ ),
+ {
+ timestamp: true
+ }
+ )
+ newDepsToLog = []
+ }
+ }
+
let depOptimizationProcessing = newDepOptimizationProcessing()
let depOptimizationProcessingQueue: DepOptimizationProcessing[] = []
const resolveEnqueuedProcessingPromises = () => {
@@ -41,40 +72,80 @@ export function createMissingImporterRegisterFn(
}
let enqueuedRerun: (() => void) | undefined
- let currentlyProcessing = true
- initialProcessingPromise.then(() => {
- currentlyProcessing = false
- enqueuedRerun?.()
- })
+ let currentlyProcessing = false
- async function rerun(ssr: boolean | undefined) {
- // debounce time to wait for new missing deps finished, issue a new
- // optimization of deps (both old and newly found) once the previous
- // optimizeDeps processing is finished
+ // If there wasn't a cache or it is outdated, perform a fast scan with esbuild
+ // to quickly find project dependencies and do a first optimize run
+ if (!cachedMetadata) {
+ currentlyProcessing = true
+
+ const scanPhaseProcessing = newDepOptimizationProcessing()
+ optimizedDeps.scanProcessing = scanPhaseProcessing.promise
+
+ const warmUp = async () => {
+ try {
+ debug(colors.green(`scanning for dependencies...`), {
+ timestamp: true
+ })
+
+ const { metadata } = optimizedDeps
+
+ const discovered = await discoverProjectDependencies(
+ config,
+ sessionTimestamp
+ )
+
+ // Respect the scan phase discover order to improve reproducibility
+ for (const depInfo of Object.values(discovered)) {
+ addOptimizedDepInfo(metadata, 'discovered', {
+ ...depInfo,
+ processing: depOptimizationProcessing.promise
+ })
+ }
+
+ debug(
+ colors.green(
+ `dependencies found: ${depsLogString(Object.keys(discovered))}`
+ ),
+ {
+ timestamp: true
+ }
+ )
+
+ scanPhaseProcessing.resolve()
+ optimizedDeps.scanProcessing = undefined
+
+ runOptimizer()
+ } catch (e) {
+ logger.error(e.message)
+ if (optimizedDeps.scanProcessing) {
+ scanPhaseProcessing.resolve()
+ optimizedDeps.scanProcessing = undefined
+ }
+ }
+ }
+
+ setTimeout(warmUp, 0)
+ }
+
+ async function runOptimizer(isRerun = false) {
+ // Ensure that rerun is called sequentially
+ enqueuedRerun = undefined
+ currentlyProcessing = true
+
+ // Ensure that a rerun will not be issued for current discovered deps
+ if (handle) clearTimeout(handle)
// a succesful completion of the optimizeDeps rerun will end up
// creating new bundled version of all current and discovered deps
// in the cache dir and a new metadata info object assigned
- // to server._optimizeDepsMetadata. A fullReload is only issued if
+ // to optimizeDeps.metadata. A fullReload is only issued if
// the previous bundled dependencies have changed.
- // if the rerun fails, server._optimizeDepsMetadata remains untouched,
+ // if the rerun fails, optimizeDeps.metadata remains untouched,
// current discovered deps are cleaned, and a fullReload is issued
- // Ensure that rerun is called sequentially
- enqueuedRerun = undefined
- currentlyProcessing = true
-
- logger.info(
- colors.yellow(
- `new dependencies found: ${Object.keys(metadata.discovered).join(
- ', '
- )}, updating...`
- ),
- {
- timestamp: true
- }
- )
+ let { metadata } = optimizedDeps
// All deps, previous known and newly discovered are rebundled,
// respect insertion order to keep the metadata file stable
@@ -85,9 +156,10 @@ export function createMissingImporterRegisterFn(
for (const dep of Object.keys(metadata.optimized)) {
newDeps[dep] = { ...metadata.optimized[dep] }
}
- // Don't clone discovered info objects, they are read after awaited
for (const dep of Object.keys(metadata.discovered)) {
- newDeps[dep] = metadata.discovered[dep]
+ // Clone the discovered info discarding its processing promise
+ const { processing, ...info } = metadata.discovered[dep]
+ newDeps[dep] = info
}
newDepsDiscovered = false
@@ -100,51 +172,87 @@ export function createMissingImporterRegisterFn(
// dependencies will be asigned this promise from this point
depOptimizationProcessing = newDepOptimizationProcessing()
- let newData: DepOptimizationMetadata | null = null
-
try {
- const optimizeDeps = await createOptimizeDepsRun(
- server.config,
- true,
- false,
- metadata,
- newDeps,
- ssr
- )
-
- const processingResult = await optimizeDeps.run()
+ const processingResult = await runOptimizeDeps(config, newDeps)
+
+ const newData = processingResult.metadata
+
+ // After a re-optimization, if the internal bundled chunks change a full page reload
+ // is required. If the files are stable, we can avoid the reload that is expensive
+ // for large applications. Comparing their fileHash we can find out if it is safe to
+ // keep the current browser state.
+ const needsReload =
+ metadata.hash !== newData.hash ||
+ Object.keys(metadata.optimized).some((dep) => {
+ return (
+ metadata.optimized[dep].fileHash !== newData.optimized[dep].fileHash
+ )
+ })
const commitProcessing = () => {
processingResult.commit()
- newData = optimizeDeps.metadata
+ // While optimizeDeps is running, new missing deps may be discovered,
+ // in which case they will keep being added to metadata.discovered
+ for (const id in metadata.discovered) {
+ if (!newData.optimized[id]) {
+ addOptimizedDepInfo(newData, 'discovered', metadata.discovered[id])
+ }
+ }
- // update ssr externals
- if (ssr) {
- server._ssrExternals = resolveSSRExternal(
- server.config,
- Object.keys(newData.optimized)
- )
+ // If we don't reload the page, we need to keep browserHash stable
+ if (!needsReload) {
+ newData.browserHash = metadata.browserHash
+ for (const dep in newData.chunks) {
+ newData.chunks[dep].browserHash = metadata.browserHash
+ }
+ for (const dep in newData.optimized) {
+ newData.optimized[dep].browserHash = (
+ metadata.optimized[dep] || metadata.discovered[dep]
+ ).browserHash
+ }
}
- // While optimizeDeps is running, new missing deps may be discovered,
- // in which case they will keep being added to metadata.discovered
- for (const o of Object.keys(metadata.discovered)) {
- if (!newData.optimized[o]) {
- newData.discovered[o] = metadata.discovered[o]
+ // Commit hash and needsInterop changes to the discovered deps info
+ // object. Allow for code to await for the discovered processing promise
+ // and use the information in the same object
+ for (const o in newData.optimized) {
+ const discovered = metadata.discovered[o]
+ if (discovered) {
+ const optimized = newData.optimized[o]
+ discovered.browserHash = optimized.browserHash
+ discovered.fileHash = optimized.fileHash
+ discovered.needsInterop = optimized.needsInterop
+ discovered.processing = undefined
}
}
- metadata = server._optimizeDepsMetadata = newData
+ if (isRerun) {
+ newDepsToLog.push(
+ ...Object.keys(newData.optimized).filter(
+ (dep) => !metadata.optimized[dep]
+ )
+ )
+ }
+
+ metadata = optimizedDeps.metadata = newData
resolveEnqueuedProcessingPromises()
}
- if (!processingResult.alteredFiles) {
+ if (!needsReload) {
commitProcessing()
- logger.info(colors.green(`✨ new dependencies pre-bundled...`), {
- timestamp: true
- })
+ if (!isDebugEnabled) {
+ if (newDepsToLogHandle) clearTimeout(newDepsToLogHandle)
+ newDepsToLogHandle = setTimeout(() => {
+ newDepsToLogHandle = undefined
+ logNewlyDiscoveredDeps()
+ }, 2 * debounceMs)
+ } else {
+ debug(colors.green(`✨ optimized dependencies unchanged`), {
+ timestamp: true
+ })
+ }
} else {
if (newDepsDiscovered) {
// There are newly discovered deps, and another rerun is about to be
@@ -153,7 +261,7 @@ export function createMissingImporterRegisterFn(
// once a rerun is committed
processingResult.cancel()
- logger.info(
+ debug(
colors.green(
`✨ delaying reload as new dependencies have been found...`
),
@@ -164,8 +272,14 @@ export function createMissingImporterRegisterFn(
} else {
commitProcessing()
+ if (!isDebugEnabled) {
+ if (newDepsToLogHandle) clearTimeout(newDepsToLogHandle)
+ newDepsToLogHandle = undefined
+ logNewlyDiscoveredDeps()
+ }
+
logger.info(
- colors.green(`✨ dependencies updated, reloading page...`),
+ colors.green(`✨ optimized dependencies changed. reloading`),
{
timestamp: true
}
@@ -202,7 +316,17 @@ export function createMissingImporterRegisterFn(
})
}
- const discoveredTimestamp = Date.now()
+ async function rerun() {
+ // debounce time to wait for new missing deps finished, issue a new
+ // optimization of deps (both old and newly found) once the previous
+ // optimizeDeps processing is finished
+ const deps = Object.keys(optimizedDeps.metadata.discovered)
+ const depsString = depsLogString(deps)
+ debug(colors.green(`new dependencies found: ${depsString}`), {
+ timestamp: true
+ })
+ runOptimizer(true)
+ }
function getDiscoveredBrowserHash(
hash: string,
@@ -210,18 +334,21 @@ export function createMissingImporterRegisterFn(
missing: Record
) {
return getHash(
- hash +
- JSON.stringify(deps) +
- JSON.stringify(missing) +
- discoveredTimestamp
+ hash + JSON.stringify(deps) + JSON.stringify(missing) + sessionTimestamp
)
}
- return function registerMissingImport(
+ function registerMissingImport(
id: string,
resolved: string,
ssr?: boolean
): OptimizedDepInfo {
+ if (optimizedDeps.scanProcessing) {
+ config.logger.error(
+ 'Vite internal error: registering missing import before initial scanning is over'
+ )
+ }
+ const { metadata } = optimizedDeps
const optimized = metadata.optimized[id]
if (optimized) {
return optimized
@@ -237,7 +364,8 @@ export function createMissingImporterRegisterFn(
return missing
}
newDepsDiscovered = true
- missing = metadata.discovered[id] = {
+ missing = addOptimizedDepInfo(metadata, 'discovered', {
+ id,
file: getOptimizedDepPath(id, server.config),
src: resolved,
// Assing a browserHash to this missing dependency that is unique to
@@ -252,15 +380,17 @@ export function createMissingImporterRegisterFn(
// loading of this pre-bundled dep needs to await for its processing
// promise to be resolved
processing: depOptimizationProcessing.promise
- }
+ })
// Debounced rerun, let other missing dependencies be discovered before
// the running next optimizeDeps
enqueuedRerun = undefined
if (handle) clearTimeout(handle)
+ if (newDepsToLogHandle) clearTimeout(newDepsToLogHandle)
+ newDepsToLogHandle = undefined
handle = setTimeout(() => {
handle = undefined
- enqueuedRerun = () => rerun(ssr)
+ enqueuedRerun = rerun
if (!currentlyProcessing) {
enqueuedRerun()
}
@@ -270,4 +400,6 @@ export function createMissingImporterRegisterFn(
// esbuild is run to generate the pre-bundle
return missing
}
+
+ return optimizedDeps
}
diff --git a/packages/vite/src/node/optimizer/scan.ts b/packages/vite/src/node/optimizer/scan.ts
index d1ac4eb249a8f3..e940617386eb35 100644
--- a/packages/vite/src/node/optimizer/scan.ts
+++ b/packages/vite/src/node/optimizer/scan.ts
@@ -123,18 +123,29 @@ export async function scanImports(config: ResolvedConfig): Promise<{
debug(`Scan completed in ${(performance.now() - start).toFixed(2)}ms:`, deps)
return {
- deps,
+ // Ensure a fixed order so hashes are stable and improve logs
+ deps: orderedDependencies(deps),
missing
}
}
+function orderedDependencies(deps: Record) {
+ const depsList = Object.entries(deps)
+ // Ensure the same browserHash for the same set of dependencies
+ depsList.sort((a, b) => a[0].localeCompare(b[0]))
+ return Object.fromEntries(depsList)
+}
+
function globEntries(pattern: string | string[], config: ResolvedConfig) {
return glob(pattern, {
cwd: config.root,
ignore: [
'**/node_modules/**',
`**/${config.build.outDir}/**`,
- `**/__tests__/**`
+ // if there aren't explicit entries, also ignore other common folders
+ ...(config.optimizeDeps.entries
+ ? []
+ : [`**/__tests__/**`, `**/coverage/**`])
],
absolute: true
})
@@ -165,7 +176,10 @@ function esbuildScanPlugin(
}
const resolved = await container.resolveId(
id,
- importer && normalizePath(importer)
+ importer && normalizePath(importer),
+ {
+ scan: true
+ }
)
const res = resolved?.id
seen.set(key, res)
diff --git a/packages/vite/src/node/plugin.ts b/packages/vite/src/node/plugin.ts
index 36674e242bd33e..354b246dd9f182 100644
--- a/packages/vite/src/node/plugin.ts
+++ b/packages/vite/src/node/plugin.ts
@@ -121,7 +121,14 @@ export interface Plugin extends RollupPlugin {
this: PluginContext,
source: string,
importer: string | undefined,
- options: { custom?: CustomPluginOptions; ssr?: boolean }
+ options: {
+ custom?: CustomPluginOptions
+ ssr?: boolean
+ /**
+ * @internal
+ */
+ scan?: boolean
+ }
): Promise | ResolveIdResult
load?(
this: PluginContext,
diff --git a/packages/vite/src/node/plugins/assetImportMetaUrl.ts b/packages/vite/src/node/plugins/assetImportMetaUrl.ts
index b0c59bed808604..a3f8e441b0f933 100644
--- a/packages/vite/src/node/plugins/assetImportMetaUrl.ts
+++ b/packages/vite/src/node/plugins/assetImportMetaUrl.ts
@@ -3,7 +3,12 @@ import MagicString from 'magic-string'
import path from 'path'
import { fileToUrl } from './asset'
import type { ResolvedConfig } from '../config'
-import { multilineCommentsRE, singlelineCommentsRE } from '../utils'
+import {
+ multilineCommentsRE,
+ singlelineCommentsRE,
+ stringsRE,
+ blankReplacer
+} from '../utils'
/**
* Convert `new URL('./foo.png', import.meta.url)` to its resolved built URL
@@ -27,12 +32,18 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
const importMetaUrlRE =
/\bnew\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*,?\s*\)/g
const noCommentsCode = code
- .replace(multilineCommentsRE, (m) => ' '.repeat(m.length))
- .replace(singlelineCommentsRE, (m) => ' '.repeat(m.length))
+ .replace(multilineCommentsRE, blankReplacer)
+ .replace(singlelineCommentsRE, blankReplacer)
+ .replace(stringsRE, (m) => `'${'\0'.repeat(m.length - 2)}'`)
+
let s: MagicString | null = null
let match: RegExpExecArray | null
while ((match = importMetaUrlRE.exec(noCommentsCode))) {
- const { 0: exp, 1: rawUrl, index } = match
+ const { 0: exp, 1: emptyUrl, index } = match
+
+ const urlStart = exp.indexOf(emptyUrl) + index
+ const urlEnd = urlStart + emptyUrl.length
+ const rawUrl = code.slice(urlStart, urlEnd)
if (!s) s = new MagicString(code)
diff --git a/packages/vite/src/node/plugins/clientInjections.ts b/packages/vite/src/node/plugins/clientInjections.ts
index e86bec0826d72f..1c9a0d393327c7 100644
--- a/packages/vite/src/node/plugins/clientInjections.ts
+++ b/packages/vite/src/node/plugins/clientInjections.ts
@@ -23,7 +23,7 @@ export function clientInjectionsPlugin(config: ResolvedConfig): Plugin {
const protocol = options.protocol || null
const timeout = options.timeout || 30000
const overlay = options.overlay !== false
- let port: number | string | false | undefined
+ let port: number | string | undefined
if (isObject(config.server.hmr)) {
port = config.server.hmr.clientPort || config.server.hmr.port
}
@@ -41,14 +41,14 @@ export function clientInjectionsPlugin(config: ResolvedConfig): Plugin {
}
return code
- .replace(/__MODE__/g, JSON.stringify(config.mode))
- .replace(/__BASE__/g, JSON.stringify(config.base))
- .replace(/__DEFINES__/g, serializeDefine(config.define || {}))
- .replace(/__HMR_PROTOCOL__/g, JSON.stringify(protocol))
- .replace(/__HMR_HOSTNAME__/g, JSON.stringify(host))
- .replace(/__HMR_PORT__/g, JSON.stringify(port))
- .replace(/__HMR_TIMEOUT__/g, JSON.stringify(timeout))
- .replace(/__HMR_ENABLE_OVERLAY__/g, JSON.stringify(overlay))
+ .replace(`__MODE__`, JSON.stringify(config.mode))
+ .replace(`__BASE__`, JSON.stringify(config.base))
+ .replace(`__DEFINES__`, serializeDefine(config.define || {}))
+ .replace(`__HMR_PROTOCOL__`, JSON.stringify(protocol))
+ .replace(`__HMR_HOSTNAME__`, JSON.stringify(host))
+ .replace(`__HMR_PORT__`, JSON.stringify(port))
+ .replace(`__HMR_TIMEOUT__`, JSON.stringify(timeout))
+ .replace(`__HMR_ENABLE_OVERLAY__`, JSON.stringify(overlay))
} else if (!options?.ssr && code.includes('process.env.NODE_ENV')) {
// replace process.env.NODE_ENV instead of defining a global
// for it to avoid shimming a `process` object during dev,
diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts
index db8e0a2679f74f..dbe9e7d1dfa00f 100644
--- a/packages/vite/src/node/plugins/css.ts
+++ b/packages/vite/src/node/plugins/css.ts
@@ -27,7 +27,7 @@ import type {
} from 'rollup'
import { dataToEsm } from '@rollup/pluginutils'
import colors from 'picocolors'
-import { CLIENT_PUBLIC_PATH } from '../constants'
+import { CLIENT_PUBLIC_PATH, SPECIAL_QUERY_RE } from '../constants'
import type { ResolveFn, ViteDevServer } from '../'
import {
getAssetFilename,
@@ -36,7 +36,7 @@ import {
checkPublicFile
} from './asset'
import MagicString from 'magic-string'
-import type * as Postcss from 'postcss'
+import type * as PostCSS from 'postcss'
import type Sass from 'sass'
// We need to disable check of extraneous import which is buggy for stylus,
// and causes the CI tests fail, see: https://github.com/vitejs/vite/pull/2860
@@ -59,9 +59,15 @@ export interface CSSOptions {
preprocessorOptions?: Record
postcss?:
| string
- | (Postcss.ProcessOptions & {
- plugins?: Postcss.Plugin[]
+ | (PostCSS.ProcessOptions & {
+ plugins?: PostCSS.Plugin[]
})
+ /**
+ * Enables css sourcemaps during dev
+ * @default false
+ * @experimental
+ */
+ devSourcemap?: boolean
}
export interface CSSModulesOptions {
@@ -163,7 +169,11 @@ export function cssPlugin(config: ResolvedConfig): Plugin {
},
async transform(raw, id, options) {
- if (!isCSSRequest(id) || commonjsProxyRE.test(id)) {
+ if (
+ !isCSSRequest(id) ||
+ commonjsProxyRE.test(id) ||
+ SPECIAL_QUERY_RE.test(id)
+ ) {
return
}
const ssr = options?.ssr === true
@@ -280,7 +290,11 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
},
async transform(css, id, options) {
- if (!isCSSRequest(id) || commonjsProxyRE.test(id)) {
+ if (
+ !isCSSRequest(id) ||
+ commonjsProxyRE.test(id) ||
+ SPECIAL_QUERY_RE.test(id)
+ ) {
return
}
@@ -301,9 +315,12 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
return `export default ${JSON.stringify(css)}`
}
- const sourcemap = this.getCombinedSourcemap()
- await injectSourcesContent(sourcemap, cleanUrl(id), config.logger)
- const cssContent = getCodeWithSourcemap('css', css, sourcemap)
+ let cssContent = css
+ if (config.css?.devSourcemap) {
+ const sourcemap = this.getCombinedSourcemap()
+ await injectSourcesContent(sourcemap, cleanUrl(id), config.logger)
+ cssContent = getCodeWithSourcemap('css', css, sourcemap)
+ }
return [
`import { updateStyle as __vite__updateStyle, removeStyle as __vite__removeStyle } from ${JSON.stringify(
@@ -341,14 +358,21 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
styles.set(id, css)
}
+ let code: string
+ if (usedRE.test(id)) {
+ if (inlined) {
+ code = `export default ${JSON.stringify(
+ await minifyCSS(css, config)
+ )}`
+ } else {
+ code = modulesCode || `export default ${JSON.stringify(css)}`
+ }
+ } else {
+ code = `export default ''`
+ }
+
return {
- code:
- modulesCode ||
- (usedRE.test(id)
- ? `export default ${JSON.stringify(
- inlined ? await minifyCSS(css, config) : css
- )}`
- : `export default ''`),
+ code,
map: { mappings: '' },
// avoid the css module from being tree-shaken so that we can retrieve
// it in renderChunk()
@@ -600,11 +624,15 @@ async function compileCSS(
): Promise<{
code: string
map?: SourceMapInput
- ast?: Postcss.Result
+ ast?: PostCSS.Result
modules?: Record
deps?: Set
}> {
- const { modules: modulesOptions, preprocessorOptions } = config.css || {}
+ const {
+ modules: modulesOptions,
+ preprocessorOptions,
+ devSourcemap
+ } = config.css || {}
const isModule = modulesOptions !== false && cssModuleRE.test(id)
// although at serve time it can work without processing, we do need to
// crawl them in order to register watch dependencies.
@@ -653,6 +681,7 @@ async function compileCSS(
}
// important: set this for relative import resolving
opts.filename = cleanUrl(id)
+ opts.enableSourcemap = devSourcemap ?? false
const preprocessResult = await preProcessor(
code,
@@ -713,7 +742,7 @@ async function compileCSS(
postcssPlugins.push(
UrlRewritePostcssPlugin({
replacer: urlReplacer
- }) as Postcss.Plugin
+ }) as PostCSS.Plugin
)
if (isModule) {
@@ -761,7 +790,9 @@ async function compileCSS(
map: {
inline: false,
annotation: false,
- sourcesContent: false
+ // postcss may return virtual files
+ // we cannot obtain content of them, so this needs to be enabled
+ sourcesContent: true
// when "prev: preprocessorMap", the result map may include duplicate filename in `postcssResult.map.sources`
// prev: preprocessorMap,
}
@@ -807,6 +838,16 @@ async function compileCSS(
}
}
+ if (!devSourcemap) {
+ return {
+ ast: postcssResult,
+ code: postcssResult.css,
+ map: { mappings: '' },
+ modules,
+ deps
+ }
+ }
+
const rawPostcssMap = postcssResult.map.toJSON()
const postcssMap = formatPostcssSourceMap(
@@ -830,19 +871,33 @@ export function formatPostcssSourceMap(
file: string
): ExistingRawSourceMap {
const inputFileDir = path.dirname(file)
- const sources = rawMap.sources
+
+ const sources: string[] = []
+ const sourcesContent: string[] = []
+ for (const [i, source] of rawMap.sources.entries()) {
// remove from sources, to prevent source map to be combined incorrectly
- .filter((source) => source !== '')
- .map((source) => {
- const cleanSource = cleanUrl(decodeURIComponent(source))
- return normalizePath(path.resolve(inputFileDir, cleanSource))
- })
+ if (source === '') continue
+
+ const cleanSource = cleanUrl(decodeURIComponent(source))
+
+ // postcss returns virtual files
+ if (/^<.+>$/.test(cleanSource)) {
+ sources.push(`\0${cleanSource}`)
+ } else {
+ sources.push(normalizePath(path.resolve(inputFileDir, cleanSource)))
+ }
+
+ if (rawMap.sourcesContent) {
+ sourcesContent.push(rawMap.sourcesContent[i])
+ }
+ }
return {
file,
mappings: rawMap.mappings,
names: rawMap.names,
sources,
+ sourcesContent,
version: rawMap.version
}
}
@@ -863,8 +918,8 @@ function combineSourcemapsIfExists(
}
interface PostCSSConfigResult {
- options: Postcss.ProcessOptions
- plugins: Postcss.Plugin[]
+ options: PostCSS.ProcessOptions
+ plugins: PostCSS.Plugin[]
}
async function resolvePostcssConfig(
@@ -910,10 +965,12 @@ type CssUrlReplacer = (
// https://drafts.csswg.org/css-syntax-3/#identifier-code-point
export const cssUrlRE =
/(?<=^|[^\w\-\u0080-\uffff])url\(\s*('[^']+'|"[^"]+"|[^'")]+)\s*\)/
+export const cssDataUriRE =
+ /(?<=^|[^\w\-\u0080-\uffff])data-uri\(\s*('[^']+'|"[^"]+"|[^'")]+)\s*\)/
export const importCssRE = /@import ('[^']+\.css'|"[^"]+\.css"|[^'")]+\.css)/
const cssImageSetRE = /image-set\(([^)]+)\)/
-const UrlRewritePostcssPlugin: Postcss.PluginCreator<{
+const UrlRewritePostcssPlugin: PostCSS.PluginCreator<{
replacer: CssUrlReplacer
}> = (opts) => {
if (!opts) {
@@ -960,6 +1017,16 @@ function rewriteCssUrls(
})
}
+function rewriteCssDataUris(
+ css: string,
+ replacer: CssUrlReplacer
+): Promise {
+ return asyncReplace(css, cssDataUriRE, async (match) => {
+ const [matched, rawUrl] = match
+ return await doUrlReplace(rawUrl, matched, replacer, 'data-uri')
+ })
+}
+
function rewriteImportCss(
css: string,
replacer: CssUrlReplacer
@@ -985,7 +1052,8 @@ function rewriteCssImageSet(
async function doUrlReplace(
rawUrl: string,
matched: string,
- replacer: CssUrlReplacer
+ replacer: CssUrlReplacer,
+ funcName: string = 'url'
) {
let wrap = ''
const first = rawUrl[0]
@@ -997,7 +1065,12 @@ async function doUrlReplace(
return matched
}
- return `url(${wrap}${await replacer(rawUrl)}${wrap})`
+ const newUrl = await replacer(rawUrl)
+ if (wrap === '' && newUrl !== encodeURI(newUrl)) {
+ // The new url might need wrapping even if the original did not have it, e.g. if a space was added during replacement
+ wrap = "'"
+ }
+ return `${funcName}(${wrap}${newUrl}${wrap})`
}
async function doImportCSSReplace(
@@ -1041,11 +1114,11 @@ async function hoistAtImports(css: string) {
return (await postcss.default([AtImportHoistPlugin]).process(css)).css
}
-const AtImportHoistPlugin: Postcss.PluginCreator = () => {
+const AtImportHoistPlugin: PostCSS.PluginCreator = () => {
return {
postcssPlugin: 'vite-hoist-at-imports',
Once(root) {
- const imports: Postcss.AtRule[] = []
+ const imports: PostCSS.AtRule[] = []
root.walkAtRules((rule) => {
if (rule.name === 'import') {
// record in reverse so that can simply prepend to preserve order
@@ -1078,6 +1151,7 @@ type StylePreprocessorOptions = {
additionalData?: PreprocessorAdditionalData
filename: string
alias: Alias[]
+ enableSourcemap: boolean
}
type SassStylePreprocessorOptions = StylePreprocessorOptions & Sass.Options
@@ -1167,7 +1241,8 @@ const scss: SassStylePreprocessor = async (
const { content: data, map: additionalMap } = await getSource(
source,
options.filename,
- options.additionalData
+ options.additionalData,
+ options.enableSourcemap
)
const finalOptions: Sass.Options = {
...options,
@@ -1175,9 +1250,13 @@ const scss: SassStylePreprocessor = async (
file: options.filename,
outFile: options.filename,
importer,
- sourceMap: true,
- omitSourceMapUrl: true,
- sourceMapRoot: path.dirname(options.filename)
+ ...(options.enableSourcemap
+ ? {
+ sourceMap: true,
+ omitSourceMapUrl: true,
+ sourceMapRoot: path.dirname(options.filename)
+ }
+ : {})
}
try {
@@ -1241,10 +1320,12 @@ async function rebaseUrls(
const content = fs.readFileSync(file, 'utf-8')
// no url()
const hasUrls = cssUrlRE.test(content)
+ // data-uri() calls
+ const hasDataUris = cssDataUriRE.test(content)
// no @import xxx.css
const hasImportCss = importCssRE.test(content)
- if (!hasUrls && !hasImportCss) {
+ if (!hasUrls && !hasDataUris && !hasImportCss) {
return { file }
}
@@ -1273,6 +1354,10 @@ async function rebaseUrls(
rebased = await rewriteCssUrls(rebased || content, rebaseFn)
}
+ if (hasDataUris) {
+ rebased = await rewriteCssDataUris(rebased || content, rebaseFn)
+ }
+
return {
file,
contents: rebased
@@ -1291,7 +1376,8 @@ const less: StylePreprocessor = async (source, root, options, resolvers) => {
const { content, map: additionalMap } = await getSource(
source,
options.filename,
- options.additionalData
+ options.additionalData,
+ options.enableSourcemap
)
let result: Less.RenderOutput | undefined
@@ -1299,10 +1385,14 @@ const less: StylePreprocessor = async (source, root, options, resolvers) => {
result = await nodeLess.render(content, {
...options,
plugins: [viteResolverPlugin, ...(options.plugins || [])],
- sourceMap: {
- outputSourceFiles: true,
- sourceMapFileInline: false
- }
+ ...(options.enableSourcemap
+ ? {
+ sourceMap: {
+ outputSourceFiles: true,
+ sourceMapFileInline: false
+ }
+ }
+ : {})
})
} catch (e) {
const error = e as Less.RenderError
@@ -1316,8 +1406,10 @@ const less: StylePreprocessor = async (source, root, options, resolvers) => {
return { code: '', errors: [normalizedError], deps: [] }
}
- const map: ExistingRawSourceMap = JSON.parse(result.map)
- delete map.sourcesContent
+ const map: ExistingRawSourceMap = result.map && JSON.parse(result.map)
+ if (map) {
+ delete map.sourcesContent
+ }
return {
code: result.css.toString(),
@@ -1408,6 +1500,7 @@ const styl: StylePreprocessor = async (source, root, options) => {
source,
options.filename,
options.additionalData,
+ options.enableSourcemap,
'\n'
)
// Get preprocessor options.imports dependencies as stylus
@@ -1417,11 +1510,13 @@ const styl: StylePreprocessor = async (source, root, options) => {
)
try {
const ref = nodeStylus(content, options)
- ref.set('sourcemap', {
- comment: false,
- inline: false,
- basePath: root
- })
+ if (options.enableSourcemap) {
+ ref.set('sourcemap', {
+ comment: false,
+ inline: false,
+ basePath: root
+ })
+ }
const result = ref.render()
@@ -1429,7 +1524,7 @@ const styl: StylePreprocessor = async (source, root, options) => {
const deps = [...ref.deps(), ...importsDeps]
// @ts-expect-error sourcemap exists
- const map: ExistingRawSourceMap = ref.sourcemap
+ const map: ExistingRawSourceMap | undefined = ref.sourcemap
return {
code: result,
@@ -1444,9 +1539,10 @@ const styl: StylePreprocessor = async (source, root, options) => {
}
function formatStylusSourceMap(
- mapBefore: ExistingRawSourceMap,
+ mapBefore: ExistingRawSourceMap | undefined,
root: string
-): ExistingRawSourceMap {
+): ExistingRawSourceMap | undefined {
+ if (!mapBefore) return undefined
const map = { ...mapBefore }
const resolveFromRoot = (p: string) => normalizePath(path.resolve(root, p))
@@ -1462,7 +1558,8 @@ function formatStylusSourceMap(
async function getSource(
source: string,
filename: string,
- additionalData?: PreprocessorAdditionalData,
+ additionalData: PreprocessorAdditionalData | undefined,
+ enableSourcemap: boolean,
sep: string = ''
): Promise<{ content: string; map?: ExistingRawSourceMap }> {
if (!additionalData) return { content: source }
@@ -1475,6 +1572,10 @@ async function getSource(
return newContent
}
+ if (!enableSourcemap) {
+ return { content: additionalData + sep + source }
+ }
+
const ms = new MagicString(source)
ms.appendLeft(0, sep)
ms.appendLeft(0, additionalData)
diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts
index c8a5617a92b253..25ad91582140c3 100644
--- a/packages/vite/src/node/plugins/html.ts
+++ b/packages/vite/src/node/plugins/html.ts
@@ -5,7 +5,8 @@ import type {
OutputAsset,
OutputBundle,
OutputChunk,
- RollupError
+ RollupError,
+ SourceMapInput
} from 'rollup'
import {
cleanUrl,
@@ -54,7 +55,7 @@ export const isHTMLRequest = (request: string): boolean =>
// HTML Proxy Caches are stored by config -> filePath -> index
export const htmlProxyMap = new WeakMap<
ResolvedConfig,
- Map>
+ Map>
>()
// HTML Proxy Transform result are stored by config
@@ -83,7 +84,7 @@ export function htmlInlineProxyPlugin(config: ResolvedConfig): Plugin {
const file = cleanUrl(id)
const url = file.replace(normalizePath(config.root), '')
const result = htmlProxyMap.get(config)!.get(url)![index]
- if (typeof result === 'string') {
+ if (result) {
return result
} else {
throw new Error(`No matching HTML proxy module found from ${id}`)
@@ -97,7 +98,7 @@ export function addToHTMLProxyCache(
config: ResolvedConfig,
filePath: string,
index: number,
- code: string
+ result: { code: string; map?: SourceMapInput }
): void {
if (!htmlProxyMap.get(config)) {
htmlProxyMap.set(config, new Map())
@@ -105,7 +106,7 @@ export function addToHTMLProxyCache(
if (!htmlProxyMap.get(config)!.get(filePath)) {
htmlProxyMap.get(config)!.set(filePath, [])
}
- htmlProxyMap.get(config)!.get(filePath)![index] = code
+ htmlProxyMap.get(config)!.get(filePath)![index] = result
}
export function addToHTMLProxyTransformResult(
@@ -284,12 +285,9 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
.join('')
//
const filePath = id.replace(normalizePath(config.root), '')
- addToHTMLProxyCache(
- config,
- filePath,
- inlineModuleIndex,
- contents
- )
+ addToHTMLProxyCache(config, filePath, inlineModuleIndex, {
+ code: contents
+ })
js += `\nimport "${id}?html-proxy&index=${inlineModuleIndex}.js"`
shouldRemove = true
}
@@ -364,11 +362,11 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
const styleNode = inlineStyle.value!
const code = styleNode.content!
const filePath = id.replace(normalizePath(config.root), '')
- addToHTMLProxyCache(config, filePath, inlineModuleIndex, code)
+ addToHTMLProxyCache(config, filePath, inlineModuleIndex, { code })
// will transform with css plugin and cache result with css-post plugin
js += `\nimport "${id}?html-proxy&inline-css&index=${inlineModuleIndex}.css"`
- // will transfrom in `applyHtmlTransforms`
+ // will transform in `applyHtmlTransforms`
s.overwrite(
styleNode.loc.start.offset,
styleNode.loc.end.offset,
@@ -382,12 +380,9 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
const styleNode = node.children.pop() as TextNode
const filePath = id.replace(normalizePath(config.root), '')
inlineModuleIndex++
- addToHTMLProxyCache(
- config,
- filePath,
- inlineModuleIndex,
- styleNode.content
- )
+ addToHTMLProxyCache(config, filePath, inlineModuleIndex, {
+ code: styleNode.content
+ })
js += `\nimport "${id}?html-proxy&index=${inlineModuleIndex}.css"`
shouldRemove = true
}
@@ -599,7 +594,6 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
}
}
- const shortEmitName = path.posix.relative(config.root, id)
// no use assets plugin because it will emit file
let match: RegExpExecArray | null
let s: MagicString | undefined
@@ -617,8 +611,9 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
if (s) {
result = s.toString()
}
+ const relativeUrlPath = path.posix.relative(config.root, id)
result = await applyHtmlTransforms(result, postHooks, {
- path: '/' + shortEmitName,
+ path: '/' + relativeUrlPath,
filename: id,
bundle,
chunk
@@ -633,6 +628,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
delete bundle[chunk.fileName]
}
+ const shortEmitName = path.relative(config.root, id)
this.emitFile({
type: 'asset',
fileName: shortEmitName,
@@ -710,6 +706,8 @@ export function resolveHtmlTransforms(
return [preHooks, postHooks]
}
+export const maybeVirtualHtmlSet = new Set()
+
export async function applyHtmlTransforms(
html: string,
hooks: IndexHtmlTransformHook[],
@@ -720,6 +718,8 @@ export async function applyHtmlTransforms(
const bodyTags: HtmlTagDescriptor[] = []
const bodyPrependTags: HtmlTagDescriptor[] = []
+ maybeVirtualHtmlSet.add(ctx.filename)
+
for (const hook of hooks) {
const res = await hook(html, ctx)
if (!res) {
diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts
index a4d2acc44db953..31e9cd76faa8a0 100644
--- a/packages/vite/src/node/plugins/importAnalysis.ts
+++ b/packages/vite/src/node/plugins/importAnalysis.ts
@@ -122,6 +122,12 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
},
async transform(source, importer, options) {
+ // In a real app `server` is always defined, but it is undefined when
+ // running src/node/server/__tests__/pluginContainer.spec.ts
+ if (!server) {
+ return null
+ }
+
const ssr = options?.ssr === true
const prettyImporter = prettifyUrl(importer, root)
@@ -159,7 +165,13 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
)
}
+ const { moduleGraph } = server
+ // since we are already in the transform phase of the importer, it must
+ // have been loaded so its entry is guaranteed in the module graph.
+ const importerModule = moduleGraph.getModuleById(importer)!
+
if (!imports.length) {
+ importerModule.isSelfAccepting = false
isDebug &&
debug(
`${timeFrom(start)} ${colors.dim(`[no imports] ${prettyImporter}`)}`
@@ -173,11 +185,6 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
let needQueryInjectHelper = false
let s: MagicString | undefined
const str = () => s || (s = new MagicString(source))
- // vite-only server context
- const { moduleGraph } = server
- // since we are already in the transform phase of the importer, it must
- // have been loaded so its entry is guaranteed in the module graph.
- const importerModule = moduleGraph.getModuleById(importer)!
const importedUrls = new Set()
const staticImportedUrls = new Set()
const acceptedUrls = new Set<{
@@ -197,19 +204,20 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
}
let importerFile = importer
- if (
- moduleListContains(config.optimizeDeps?.exclude, url) &&
- server._optimizeDepsMetadata
- ) {
- // if the dependency encountered in the optimized file was excluded from the optimization
- // the dependency needs to be resolved starting from the original source location of the optimized file
- // because starting from node_modules/.vite will not find the dependency if it was not hoisted
- // (that is, if it is under node_modules directory in the package source of the optimized file)
- for (const optimizedModule of Object.values(
- server._optimizeDepsMetadata.optimized
- )) {
- if (optimizedModule.file === importerModule.file) {
- importerFile = optimizedModule.src
+ if (moduleListContains(config.optimizeDeps?.exclude, url)) {
+ const optimizedDeps = server._optimizedDeps
+ if (optimizedDeps) {
+ await optimizedDeps.scanProcessing
+
+ // if the dependency encountered in the optimized file was excluded from the optimization
+ // the dependency needs to be resolved starting from the original source location of the optimized file
+ // because starting from node_modules/.vite will not find the dependency if it was not hoisted
+ // (that is, if it is under node_modules directory in the package source of the optimized file)
+ for (const optimizedModule of optimizedDeps.metadata.depInfoList) {
+ if (!optimizedModule.src) continue // Ignore chunks
+ if (optimizedModule.file === importerModule.file) {
+ importerFile = optimizedModule.src
+ }
}
}
}
@@ -439,6 +447,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
importRewrites.push(async () => {
let rewriteDone = false
if (
+ server?._optimizedDeps &&
isOptimizedDepFile(resolvedId, config) &&
!resolvedId.match(optimizedDepChunkRE)
) {
@@ -450,7 +459,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
const file = cleanUrl(resolvedId) // Remove ?v={hash}
const needsInterop = await optimizedDepNeedsInterop(
- server._optimizeDepsMetadata!,
+ server._optimizedDeps!.metadata,
file
)
@@ -516,7 +525,10 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
}
} else if (!importer.startsWith(clientDir) && !ssr) {
// check @vite-ignore which suppresses dynamic import warning
- const hasViteIgnore = /\/\*\s*@vite-ignore\s*\*\//.test(rawUrl)
+ const hasViteIgnore = /\/\*\s*@vite-ignore\s*\*\//.test(
+ // complete expression inside parens
+ source.slice(dynamicIndex + 1, end)
+ )
const url = rawUrl
.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '')
diff --git a/packages/vite/src/node/plugins/importAnalysisBuild.ts b/packages/vite/src/node/plugins/importAnalysisBuild.ts
index c8bef0231af757..91ce663b9f8111 100644
--- a/packages/vite/src/node/plugins/importAnalysisBuild.ts
+++ b/packages/vite/src/node/plugins/importAnalysisBuild.ts
@@ -86,6 +86,7 @@ function preload(baseModule: () => Promise<{}>, deps?: string[]) {
export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin {
const ssr = !!config.build.ssr
const insertPreload = !(ssr || !!config.build.lib)
+ const isWorker = config.isWorker
const scriptRel = config.build.polyfillModulePreload
? `'modulepreload'`
@@ -120,6 +121,11 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin {
return
}
+ if (isWorker) {
+ // preload method use `document` and can't run in the worker
+ return
+ }
+
await init
let imports: readonly ImportSpecifier[] = []
@@ -132,7 +138,6 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin {
if (!imports.length) {
return null
}
-
let s: MagicString | undefined
const str = () => s || (s = new MagicString(source))
let needPreloadHelper = false
@@ -241,7 +246,7 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin {
},
generateBundle({ format }, bundle) {
- if (format !== 'es' || ssr) {
+ if (format !== 'es' || ssr || isWorker) {
return
}
diff --git a/packages/vite/src/node/plugins/index.ts b/packages/vite/src/node/plugins/index.ts
index d5a45eb085b0b9..2d34b99aebf1c5 100644
--- a/packages/vite/src/node/plugins/index.ts
+++ b/packages/vite/src/node/plugins/index.ts
@@ -9,7 +9,7 @@ import { importAnalysisPlugin } from './importAnalysis'
import { cssPlugin, cssPostPlugin } from './css'
import { assetPlugin } from './asset'
import { clientInjectionsPlugin } from './clientInjections'
-import { htmlInlineProxyPlugin } from './html'
+import { buildHtmlPlugin, htmlInlineProxyPlugin } from './html'
import { wasmPlugin } from './wasm'
import { modulePreloadPolyfillPlugin } from './modulePreloadPolyfill'
import { webWorkerPlugin } from './worker'
@@ -64,12 +64,13 @@ export async function resolvePlugins(
),
wasmPlugin(config),
webWorkerPlugin(config),
- workerImportMetaUrlPlugin(config),
assetPlugin(config),
...normalPlugins,
definePlugin(config),
cssPostPlugin(config),
config.build.ssr ? ssrRequireHookPlugin(config) : null,
+ isBuild && buildHtmlPlugin(config),
+ workerImportMetaUrlPlugin(config),
...buildPlugins.pre,
...postPlugins,
...buildPlugins.post,
diff --git a/packages/vite/src/node/plugins/optimizedDeps.ts b/packages/vite/src/node/plugins/optimizedDeps.ts
index 8fbdca8d08905f..adab1bd9756251 100644
--- a/packages/vite/src/node/plugins/optimizedDeps.ts
+++ b/packages/vite/src/node/plugins/optimizedDeps.ts
@@ -3,7 +3,7 @@ import type { Plugin } from '../plugin'
import colors from 'picocolors'
import { DEP_VERSION_RE } from '../constants'
import { cleanUrl, createDebugger } from '../utils'
-import { isOptimizedDepFile, optimizeDepInfoFromFile } from '../optimizer'
+import { isOptimizedDepFile, optimizedDepInfoFromFile } from '../optimizer'
import type { ViteDevServer } from '..'
export const ERR_OPTIMIZE_DEPS_PROCESSING_ERROR =
@@ -25,7 +25,7 @@ export function optimizedDepsPlugin(): Plugin {
async load(id) {
if (server && isOptimizedDepFile(id, server.config)) {
- const metadata = server?._optimizeDepsMetadata
+ const metadata = server?._optimizedDeps?.metadata
if (metadata) {
const file = cleanUrl(id)
const versionMatch = id.match(DEP_VERSION_RE)
@@ -34,7 +34,7 @@ export function optimizedDepsPlugin(): Plugin {
: undefined
// Search in both the currently optimized and newly discovered deps
- const info = optimizeDepInfoFromFile(metadata, file)
+ const info = optimizedDepInfoFromFile(metadata, file)
if (info) {
if (browserHash && info.browserHash !== browserHash) {
throwOutdatedRequest(id)
@@ -49,9 +49,9 @@ export function optimizedDepsPlugin(): Plugin {
throwProcessingError(id)
return
}
- const newMetadata = server._optimizeDepsMetadata
+ const newMetadata = server._optimizedDeps?.metadata
if (metadata !== newMetadata) {
- const currentInfo = optimizeDepInfoFromFile(newMetadata!, file)
+ const currentInfo = optimizedDepInfoFromFile(newMetadata!, file)
if (info.browserHash !== currentInfo?.browserHash) {
throwOutdatedRequest(id)
}
diff --git a/packages/vite/src/node/plugins/preAlias.ts b/packages/vite/src/node/plugins/preAlias.ts
index 75a0d8e5e6f9dc..dadb16aa4c28a9 100644
--- a/packages/vite/src/node/plugins/preAlias.ts
+++ b/packages/vite/src/node/plugins/preAlias.ts
@@ -13,9 +13,9 @@ export function preAliasPlugin(): Plugin {
configureServer(_server) {
server = _server
},
- resolveId(id, importer, options) {
- if (!options?.ssr && bareImportRE.test(id)) {
- return tryOptimizedResolve(id, server, importer)
+ async resolveId(id, importer, options) {
+ if (!options?.ssr && bareImportRE.test(id) && !options?.scan) {
+ return await tryOptimizedResolve(id, server, importer)
}
}
}
diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts
index 5dfaffafcbb7e4..10e2989af1114f 100644
--- a/packages/vite/src/node/plugins/resolve.ts
+++ b/packages/vite/src/node/plugins/resolve.ts
@@ -7,6 +7,7 @@ import {
SPECIAL_QUERY_RE,
DEFAULT_EXTENSIONS,
DEFAULT_MAIN_FIELDS,
+ KNOWN_ESM_MAIN_FIELDS,
OPTIMIZABLE_ENTRY_RE,
DEP_VERSION_RE
} from '../constants'
@@ -33,7 +34,8 @@ import {
import {
createIsOptimizedDepUrl,
isOptimizedDepFile,
- optimizeDepInfoFromFile
+ optimizedDepInfoFromFile,
+ optimizedDepInfoFromId
} from '../optimizer'
import type { OptimizedDepInfo } from '../optimizer'
import type { ViteDevServer, SSROptions } from '..'
@@ -83,6 +85,8 @@ export interface InternalResolveOptions extends ResolveOptions {
// should also try import from `.ts/tsx/mts/cts` source file as fallback.
isFromTsImporter?: boolean
tryEsmOnly?: boolean
+ // True when resolving during the scan phase to discover dependencies
+ scan?: boolean
}
export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
@@ -106,7 +110,7 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
isOptimizedDepUrl = createIsOptimizedDepUrl(server.config)
},
- resolveId(id, importer, resolveOpts) {
+ async resolveId(id, importer, resolveOpts) {
const ssr = resolveOpts?.ssr === true
if (id.startsWith(browserExternalId)) {
return id
@@ -127,7 +131,8 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
isRequire,
...baseOptions,
- isFromTsImporter: isTsRequest(importer ?? '')
+ isFromTsImporter: isTsRequest(importer ?? ''),
+ scan: resolveOpts?.scan ?? baseOptions.scan
}
let res: string | PartialResolvedId | undefined
@@ -136,9 +141,10 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
// tryFileResolve or /fs/ resolution but these files may not yet
// exists if we are in the middle of a deps re-processing
if (asSrc && isOptimizedDepUrl?.(id)) {
- return id.startsWith(FS_PREFIX)
+ const optimizedPath = id.startsWith(FS_PREFIX)
? fsPathFromId(id)
: normalizePath(ensureVolumeInPath(path.resolve(root, id.slice(1))))
+ return optimizedPath
}
// explicit fs paths that starts with /@fs/*
@@ -169,12 +175,15 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
const normalizedFsPath = normalizePath(fsPath)
- if (server && isOptimizedDepFile(normalizedFsPath, server!.config)) {
+ if (
+ server?._optimizedDeps &&
+ isOptimizedDepFile(normalizedFsPath, server!.config)
+ ) {
// Optimized files could not yet exist in disk, resolve to the full path
// Inject the current browserHash version if the path doesn't have one
if (!normalizedFsPath.match(DEP_VERSION_RE)) {
- const browserHash = optimizeDepInfoFromFile(
- server._optimizeDepsMetadata!,
+ const browserHash = optimizedDepInfoFromFile(
+ server._optimizedDeps!.metadata!,
normalizedFsPath
)?.browserHash
if (browserHash) {
@@ -252,7 +261,8 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
asSrc &&
server &&
!ssr &&
- (res = tryOptimizedResolve(id, server, importer))
+ !options.scan &&
+ (res = await tryOptimizedResolve(id, server, importer))
) {
return res
}
@@ -323,23 +333,28 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
}
}
-function tryFsResolve(
- fsPath: string,
- options: InternalResolveOptions,
- tryIndex = true,
- targetWeb = true
-): string | undefined {
- let file = fsPath
+function splitFileAndPostfix(path: string) {
+ let file = path
let postfix = ''
- let postfixIndex = fsPath.indexOf('?')
+ let postfixIndex = path.indexOf('?')
if (postfixIndex < 0) {
- postfixIndex = fsPath.indexOf('#')
+ postfixIndex = path.indexOf('#')
}
if (postfixIndex > 0) {
- file = fsPath.slice(0, postfixIndex)
- postfix = fsPath.slice(postfixIndex)
+ file = path.slice(0, postfixIndex)
+ postfix = path.slice(postfixIndex)
}
+ return { file, postfix }
+}
+
+function tryFsResolve(
+ fsPath: string,
+ options: InternalResolveOptions,
+ tryIndex = true,
+ targetWeb = true
+): string | undefined {
+ const { file, postfix } = splitFileAndPostfix(fsPath)
let res: string | undefined
@@ -606,7 +621,8 @@ export function tryNodeResolve(
if (
!resolved.includes('node_modules') || // linked
!server || // build
- !server._registerMissingImport // initial esbuild scan phase
+ !server._optimizedDeps || // resolving before listening to the server
+ options.scan // initial esbuild scan phase
) {
return { id: resolved }
}
@@ -627,14 +643,17 @@ export function tryNodeResolve(
// otherwise we may introduce duplicated modules for externalized files
// from pre-bundled deps.
- const versionHash = server._optimizeDepsMetadata?.browserHash
+ const versionHash = server._optimizedDeps!.metadata.browserHash
if (versionHash && isJsType) {
resolved = injectQuery(resolved, `v=${versionHash}`)
}
} else {
// this is a missing import, queue optimize-deps re-run and
// get a resolved its optimized info
- const optimizedInfo = server._registerMissingImport!(id, resolved, ssr)
+ const optimizedInfo = server._optimizedDeps!.registerMissingImport(
+ id,
+ resolved
+ )
resolved = getOptimizedUrl(optimizedInfo)
}
return { id: resolved! }
@@ -644,24 +663,20 @@ export function tryNodeResolve(
const getOptimizedUrl = (optimizedData: OptimizedDepInfo) =>
`${optimizedData.file}?v=${optimizedData.browserHash}`
-export function tryOptimizedResolve(
+export async function tryOptimizedResolve(
id: string,
server: ViteDevServer,
importer?: string
-): string | undefined {
- const depData = server._optimizeDepsMetadata
+): Promise {
+ const optimizedDeps = server._optimizedDeps
- if (!depData) return
+ if (!optimizedDeps) return
- // check if id has been optimized
- const isOptimized = depData.optimized[id]
- if (isOptimized) {
- return getOptimizedUrl(isOptimized)
- }
+ await optimizedDeps.scanProcessing
- const isChunk = depData.chunks[id]
- if (isChunk) {
- return getOptimizedUrl(isChunk)
+ const depInfo = optimizedDepInfoFromId(optimizedDeps.metadata, id)
+ if (depInfo) {
+ return getOptimizedUrl(depInfo)
}
if (!importer) return
@@ -669,7 +684,10 @@ export function tryOptimizedResolve(
// further check if id is imported by nested dependency
let resolvedSrc: string | undefined
- for (const [pkgPath, optimizedData] of Object.entries(depData.optimized)) {
+ for (const optimizedData of optimizedDeps.metadata.depInfoList) {
+ if (!optimizedData.src) continue // Ignore chunks
+
+ const pkgPath = optimizedData.id
// check for scenarios, e.g.
// pkgPath => "my-lib > foo"
// id => "foo"
@@ -726,7 +744,11 @@ export function resolvePackageEntry(
: isObject(data.browser) && data.browser['.']
if (browserEntry) {
// check if the package also has a "module" field.
- if (typeof data.module === 'string' && data.module !== browserEntry) {
+ if (
+ !options.isRequire &&
+ typeof data.module === 'string' &&
+ data.module !== browserEntry
+ ) {
// if both are present, we may have a problem: some package points both
// to ESM, with "module" targeting Node.js, while some packages points
// "module" to browser ESM and "browser" to UMD.
@@ -756,6 +778,11 @@ export function resolvePackageEntry(
if (!entryPoint || entryPoint.endsWith('.mjs')) {
for (const field of options.mainFields || DEFAULT_MAIN_FIELDS) {
+ // If the initiator is a `require` call, don't use the ESM entries
+ if (options.isRequire && KNOWN_ESM_MAIN_FIELDS.includes(field)) {
+ continue
+ }
+
if (typeof data[field] === 'string') {
entryPoint = data[field]
break
@@ -826,6 +853,7 @@ function resolveExports(
if (options.conditions) {
conditions.push(...options.conditions)
}
+
return _resolveExports(pkg, key, {
browser: targetWeb,
require: options.isRequire,
@@ -856,12 +884,14 @@ function resolveDeepImport(
// map relative based on exports data
if (exportsField) {
if (isObject(exportsField) && !Array.isArray(exportsField)) {
- relativeId = resolveExports(
- data,
- cleanUrl(relativeId),
- options,
- targetWeb
- )
+ // resolve without postfix (see #7098)
+ const { file, postfix } = splitFileAndPostfix(relativeId)
+ const exportsId = resolveExports(data, file, options, targetWeb)
+ if (exportsId !== undefined) {
+ relativeId = exportsId + postfix
+ } else {
+ relativeId = undefined
+ }
} else {
// not exposed
relativeId = undefined
@@ -873,9 +903,11 @@ function resolveDeepImport(
)
}
} else if (targetWeb && isObject(browserField)) {
- const mapped = mapWithBrowserField(relativeId, browserField)
+ // resolve without postfix (see #7098)
+ const { file, postfix } = splitFileAndPostfix(relativeId)
+ const mapped = mapWithBrowserField(file, browserField)
if (mapped) {
- relativeId = mapped
+ relativeId = mapped + postfix
} else if (mapped === false) {
return (webResolvedImports[id] = browserExternalId)
}
diff --git a/packages/vite/src/node/plugins/worker.ts b/packages/vite/src/node/plugins/worker.ts
index 70bfd916e21cab..4113b7153f9b35 100644
--- a/packages/vite/src/node/plugins/worker.ts
+++ b/packages/vite/src/node/plugins/worker.ts
@@ -6,13 +6,71 @@ import type Rollup from 'rollup'
import { ENV_PUBLIC_PATH } from '../constants'
import path from 'path'
import { onRollupWarning } from '../build'
+import type { TransformPluginContext, EmittedFile } from 'rollup'
+
+interface WorkerCache {
+ // save worker bundle emitted files avoid overwrites the same file.
+ //
+ assets: Map
+ chunks: Map
+ // worker bundle don't deps on any more worker runtime info an id only had an result.
+ // save worker bundled file id to avoid repeated execution of bundles
+ //
+ bundle: Map
+ // nested worker bundle context don't had file what emitted by outside bundle
+ // save the hash to id to rewrite truth id.
+ //
+ emitted: Map
+}
const WorkerFileId = 'worker_file'
+const workerCache = new WeakMap()
+
+function emitWorkerFile(
+ ctx: Rollup.TransformPluginContext,
+ config: ResolvedConfig,
+ asset: EmittedFile,
+ type: 'assets' | 'chunks'
+): string {
+ const fileName = asset.fileName!
+ const workerMap = workerCache.get(config)!
+
+ if (workerMap[type].has(fileName)) {
+ return workerMap[type].get(fileName)!
+ }
+ const hash = ctx.emitFile(asset)
+ workerMap[type].set(fileName, hash)
+ workerMap.emitted.set(hash, fileName)
+ return hash
+}
+
+function emitWorkerAssets(
+ ctx: Rollup.TransformPluginContext,
+ config: ResolvedConfig,
+ asset: EmittedFile
+) {
+ const { format } = config.worker
+ return emitWorkerFile(
+ ctx,
+ config,
+ asset,
+ format === 'es' ? 'chunks' : 'assets'
+ )
+}
+
+function emitWorkerChunks(
+ ctx: Rollup.TransformPluginContext,
+ config: ResolvedConfig,
+ asset: EmittedFile
+) {
+ return emitWorkerFile(ctx, config, asset, 'chunks')
+}
export async function bundleWorkerEntry(
ctx: Rollup.TransformPluginContext,
config: ResolvedConfig,
- id: string
+ id: string,
+ query: Record | null
): Promise {
// bundle the file as entry to support imports
const rollup = require('rollup') as typeof Rollup
@@ -26,22 +84,24 @@ export async function bundleWorkerEntry(
},
preserveEntrySignatures: false
})
- let code: string
+ let chunk: Rollup.OutputChunk
try {
const {
- output: [outputCode, ...outputChunks]
+ output: [outputChunk, ...outputChunks]
} = await bundle.generate({
format,
sourcemap: config.build.sourcemap
})
- code = outputCode.code
+ chunk = outputChunk
outputChunks.forEach((outputChunk) => {
if (outputChunk.type === 'asset') {
- ctx.emitFile(outputChunk)
- }
- if (outputChunk.type === 'chunk') {
- ctx.emitFile({
- fileName: `${config.build.assetsDir}/${outputChunk.fileName}`,
+ emitWorkerAssets(ctx, config, outputChunk)
+ } else if (outputChunk.type === 'chunk') {
+ emitWorkerChunks(ctx, config, {
+ fileName: path.posix.join(
+ config.build.assetsDir,
+ outputChunk.fileName
+ ),
source: outputChunk.code,
type: 'asset'
})
@@ -50,15 +110,104 @@ export async function bundleWorkerEntry(
} finally {
await bundle.close()
}
+ return emitSourcemapForWorkerEntry(ctx, config, id, query, chunk)
+}
+
+function emitSourcemapForWorkerEntry(
+ context: TransformPluginContext,
+ config: ResolvedConfig,
+ id: string,
+ query: Record | null,
+ chunk: Rollup.OutputChunk
+): Buffer {
+ let { code, map: sourcemap } = chunk
+ if (sourcemap) {
+ if (config.build.sourcemap === 'inline') {
+ // Manually add the sourcemap to the code if configured for inline sourcemaps.
+ // TODO: Remove when https://github.com/rollup/rollup/issues/3913 is resolved
+ // Currently seems that it won't be resolved until Rollup 3
+ const dataUrl = sourcemap.toUrl()
+ code += `//# sourceMappingURL=${dataUrl}`
+ } else if (
+ config.build.sourcemap === 'hidden' ||
+ config.build.sourcemap === true
+ ) {
+ const basename = path.parse(cleanUrl(id)).name
+ const data = sourcemap.toString()
+ const content = Buffer.from(data)
+ const contentHash = getAssetHash(content)
+ const fileName = `${basename}.${contentHash}.js.map`
+ const filePath = path.posix.join(config.build.assetsDir, fileName)
+ if (!context.cache.has(contentHash)) {
+ context.cache.set(contentHash, true)
+ context.emitFile({
+ fileName: filePath,
+ type: 'asset',
+ source: data
+ })
+ }
+
+ // Emit the comment that tells the JS debugger where it can find the
+ // sourcemap file.
+ // 'hidden' causes the sourcemap file to be created but
+ // the comment in the file to be omitted.
+ if (config.build.sourcemap === true) {
+ // inline web workers need to use the full sourcemap path
+ // non-inline web workers can use a relative path
+ const sourceMapUrl = query?.inline != null ? filePath : fileName
+ code += `//# sourceMappingURL=${sourceMapUrl}`
+ }
+ }
+ }
+
return Buffer.from(code)
}
+export async function workerFileToUrl(
+ ctx: Rollup.TransformPluginContext,
+ config: ResolvedConfig,
+ id: string,
+ query: Record | null
+): Promise {
+ const workerMap = workerCache.get(config)!
+
+ let hash = workerMap.bundle.get(id)
+ if (hash) {
+ // rewrite truth id, no need to replace by asset plugin
+ return config.base + workerMap.emitted.get(hash)!
+ }
+ const code = await bundleWorkerEntry(ctx, config, id, query)
+ const basename = path.parse(cleanUrl(id)).name
+ const contentHash = getAssetHash(code)
+ const fileName = path.posix.join(
+ config.build.assetsDir,
+ `${basename}.${contentHash}.js`
+ )
+ hash = emitWorkerAssets(ctx, config, {
+ fileName,
+ type: 'asset',
+ source: code
+ })
+ workerMap.bundle.set(id, hash)
+ return `__VITE_ASSET__${hash}__`
+}
+
export function webWorkerPlugin(config: ResolvedConfig): Plugin {
const isBuild = config.command === 'build'
+ const isWorker = config.isWorker
return {
name: 'vite:worker',
+ buildStart() {
+ workerCache.set(config, {
+ assets: new Map(),
+ chunks: new Map(),
+ bundle: new Map(),
+ emitted: new Map()
+ })
+ },
+
load(id) {
if (isBuild) {
const parsedQuery = parseRequest(id)
@@ -87,12 +236,13 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
let url: string
if (isBuild) {
- const code = await bundleWorkerEntry(this, config, id)
if (query.inline != null) {
+ const code = await bundleWorkerEntry(this, config, id, query)
const { format } = config.worker
const workerOptions = format === 'es' ? '{type: "module"}' : '{}'
// inline as blob data url
- return `const encodedJs = "${code.toString('base64')}";
+ return {
+ code: `const encodedJs = "${code.toString('base64')}";
const blob = typeof window !== "undefined" && window.Blob && new Blob([atob(encodedJs)], { type: "text/javascript;charset=utf-8" });
export default function WorkerWrapper() {
const objURL = blob && (window.URL || window.webkitURL).createObjectURL(blob);
@@ -101,19 +251,13 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
} finally {
objURL && (window.URL || window.webkitURL).revokeObjectURL(objURL);
}
- }`
+ }`,
+
+ // Empty sourcemap to supress Rollup warning
+ map: { mappings: '' }
+ }
} else {
- const basename = path.parse(cleanUrl(id)).name
- const contentHash = getAssetHash(code)
- const fileName = path.posix.join(
- config.build.assetsDir,
- `${basename}.${contentHash}.js`
- )
- url = `__VITE_ASSET__${this.emitFile({
- fileName,
- type: 'asset',
- source: code
- })}__`
+ url = await workerFileToUrl(this, config, id, query)
}
} else {
url = await fileToUrl(cleanUrl(id), config, this)
@@ -124,11 +268,20 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
query.sharedworker != null ? 'SharedWorker' : 'Worker'
const workerOptions = { type: 'module' }
- return `export default function WorkerWrapper() {
- return new ${workerConstructor}(${JSON.stringify(
- url
- )}, ${JSON.stringify(workerOptions, null, 2)})
- }`
+ return {
+ code: `export default function WorkerWrapper() {
+ return new ${workerConstructor}(${JSON.stringify(
+ url
+ )}, ${JSON.stringify(workerOptions, null, 2)})
+ }`,
+ map: { mappings: '' } // Empty sourcemap to supress Rolup warning
+ }
+ },
+
+ renderChunk(code) {
+ if (isWorker && code.includes('import.meta.url')) {
+ return code.replace('import.meta.url', 'self.location.href')
+ }
}
}
}
diff --git a/packages/vite/src/node/plugins/workerImportMetaUrl.ts b/packages/vite/src/node/plugins/workerImportMetaUrl.ts
index f3ed3cf1b8cbe0..c9a2903d9a4142 100644
--- a/packages/vite/src/node/plugins/workerImportMetaUrl.ts
+++ b/packages/vite/src/node/plugins/workerImportMetaUrl.ts
@@ -1,20 +1,22 @@
import JSON5 from 'json5'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
-import { getAssetHash, fileToUrl } from './asset'
+import { fileToUrl } from './asset'
import {
blankReplacer,
cleanUrl,
injectQuery,
multilineCommentsRE,
- singlelineCommentsRE
+ singlelineCommentsRE,
+ stringsRE
} from '../utils'
import path from 'path'
-import { bundleWorkerEntry } from './worker'
+import { workerFileToUrl } from './worker'
import { parseRequest } from '../utils'
import { ENV_ENTRY, ENV_PUBLIC_PATH } from '../constants'
import MagicString from 'magic-string'
import type { ViteDevServer } from '..'
+import type { RollupError } from 'rollup'
type WorkerType = 'classic' | 'module' | 'ignore'
@@ -25,14 +27,26 @@ function getWorkerType(
noCommentsCode: string,
i: number
): WorkerType {
+ function err(e: string, pos: number) {
+ const error = new Error(e) as RollupError
+ error.pos = pos
+ throw error
+ }
+
const commaIndex = noCommentsCode.indexOf(',', i)
if (commaIndex === -1) {
return 'classic'
}
const endIndex = noCommentsCode.indexOf(')', i)
+ // case: ') ... ,' mean no worker options params
+ if (commaIndex > endIndex) {
+ return 'classic'
+ }
+
// need to find in comment code
let workerOptsString = code.substring(commaIndex + 1, endIndex)
+
const hasViteIgnore = /\/\*\s*@vite-ignore\s*\*\//.test(workerOptsString)
if (hasViteIgnore) {
return 'ignore'
@@ -49,9 +63,10 @@ function getWorkerType(
workerOpts = JSON5.parse(workerOptsString)
} catch (e) {
// can't parse by JSON5, so the worker options had unexpect char.
- throw new Error(
+ err(
'Vite is unable to parse the worker options as the value is not static.' +
- 'To ignore this error, please use /* @vite-ignore */ in the worker options.'
+ 'To ignore this error, please use /* @vite-ignore */ in the worker options.',
+ commaIndex + 1
)
}
@@ -108,12 +123,21 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
const noCommentsCode = code
.replace(multilineCommentsRE, blankReplacer)
.replace(singlelineCommentsRE, blankReplacer)
+
+ const noStringCode = noCommentsCode.replace(
+ stringsRE,
+ (m) => `'${' '.repeat(m.length - 2)}'`
+ )
let match: RegExpExecArray | null
let s: MagicString | null = null
- while ((match = importMetaUrlRE.exec(noCommentsCode))) {
- const { 0: allExp, 2: exp, 3: rawUrl, index } = match
+ while ((match = importMetaUrlRE.exec(noStringCode))) {
+ const { 0: allExp, 2: exp, 3: emptyUrl, index } = match
const urlIndex = allExp.indexOf(exp) + index
+ const urlStart = allExp.indexOf(emptyUrl) + index
+ const urlEnd = urlStart + emptyUrl.length
+ const rawUrl = code.slice(urlStart, urlEnd)
+
if (options?.ssr) {
this.error(
`\`new URL(url, import.meta.url)\` is not supported in SSR.`,
@@ -138,18 +162,7 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
const file = path.resolve(path.dirname(id), rawUrl.slice(1, -1))
let url: string
if (isBuild) {
- const content = await bundleWorkerEntry(this, config, file)
- const basename = path.parse(cleanUrl(file)).name
- const contentHash = getAssetHash(content)
- const fileName = path.posix.join(
- config.build.assetsDir,
- `${basename}.${contentHash}.js`
- )
- url = `__VITE_ASSET__${this.emitFile({
- fileName,
- type: 'asset',
- source: content
- })}__`
+ url = await workerFileToUrl(this, config, file, query)
} else {
url = await fileToUrl(cleanUrl(file), config, this)
url = injectQuery(url, WORKER_FILE_ID)
diff --git a/packages/vite/src/node/preview.ts b/packages/vite/src/node/preview.ts
index 56dee04e2e2e07..c00f62a9cb8f0c 100644
--- a/packages/vite/src/node/preview.ts
+++ b/packages/vite/src/node/preview.ts
@@ -78,8 +78,9 @@ export async function preview(
}
// proxy
- if (config.preview.proxy) {
- app.use(proxyMiddleware(httpServer, config))
+ const { proxy } = config.preview
+ if (proxy) {
+ app.use(proxyMiddleware(httpServer, proxy, config))
}
app.use(compression())
diff --git a/packages/vite/src/node/server/hmr.ts b/packages/vite/src/node/server/hmr.ts
index edb73785247b6f..8d33554706dee2 100644
--- a/packages/vite/src/node/server/hmr.ts
+++ b/packages/vite/src/node/server/hmr.ts
@@ -18,7 +18,7 @@ const normalizedClientDir = normalizePath(CLIENT_DIR)
export interface HmrOptions {
protocol?: string
host?: string
- port?: number | false
+ port?: number
clientPort?: number
path?: string
timeout?: number
@@ -44,6 +44,7 @@ export async function handleHMRUpdate(
): Promise {
const { ws, config, moduleGraph } = server
const shortFile = getShortName(file, config.root)
+ const fileName = path.basename(file)
const isConfig = file === config.configFile
const isConfigDependency = config.configFileDependencies.some(
@@ -51,7 +52,7 @@ export async function handleHMRUpdate(
)
const isEnv =
config.inlineConfig.envFile !== false &&
- (file === '.env' || file.startsWith('.env.'))
+ (fileName === '.env' || fileName.startsWith('.env.'))
if (isConfig || isConfigDependency || isEnv) {
// auto restart server
debugHmr(`[config change] ${colors.dim(shortFile)}`)
@@ -225,6 +226,13 @@ function propagateUpdate(
}>,
currentChain: ModuleNode[] = [node]
): boolean /* hasDeadEnd */ {
+ // #7561
+ // if the imports of `node` have not been analyzed, then `node` has not
+ // been loaded in the browser and we should stop propagation.
+ if (node.id && node.isSelfAccepting === undefined) {
+ return false
+ }
+
if (node.isSelfAccepting) {
boundaries.add({
boundary: node,
diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts
index d56a6a705d5416..de80ac1147ff0f 100644
--- a/packages/vite/src/node/server/index.ts
+++ b/packages/vite/src/node/server/index.ts
@@ -44,8 +44,6 @@ import { transformRequest } from './transformRequest'
import type { ESBuildTransformResult } from '../plugins/esbuild'
import { transformWithEsbuild } from '../plugins/esbuild'
import type { TransformOptions as EsbuildTransformOptions } from 'esbuild'
-import type { DepOptimizationMetadata, OptimizedDepInfo } from '../optimizer'
-import { createOptimizeDepsRun } from '../optimizer'
import { ssrLoadModule } from '../ssr/ssrModuleLoader'
import { resolveSSRExternal } from '../ssr/ssrExternal'
import {
@@ -53,7 +51,8 @@ import {
ssrRewriteStacktrace
} from '../ssr/ssrStacktrace'
import { ssrTransform } from '../ssr/ssrTransform'
-import { createMissingImporterRegisterFn } from '../optimizer/registerMissing'
+import { createOptimizedDeps } from '../optimizer/registerMissing'
+import type { OptimizedDeps } from '../optimizer'
import { resolveHostname } from '../utils'
import { searchForWorkspaceRoot } from './searchRoot'
import { CLIENT_DIR } from '../constants'
@@ -257,7 +256,7 @@ export interface ViteDevServer {
/**
* @internal
*/
- _optimizeDepsMetadata: DepOptimizationMetadata | null
+ _optimizedDeps: OptimizedDeps | null
/**
* Deps that are externalized
* @internal
@@ -284,16 +283,6 @@ export interface ViteDevServer {
* @internal
*/
_forceOptimizeOnRestart: boolean
- /**
- * @internal
- */
- _registerMissingImport:
- | ((
- id: string,
- resolved: string,
- ssr: boolean | undefined
- ) => OptimizedDepInfo)
- | null
/**
* @internal
*/
@@ -372,16 +361,18 @@ export async function createServer(
},
transformIndexHtml: null!, // to be immediately set
async ssrLoadModule(url, opts?: { fixStacktrace?: boolean }) {
- let configFileDependencies: string[] = []
- const metadata = server._optimizeDepsMetadata
- if (metadata) {
- configFileDependencies = Object.keys(metadata.optimized)
+ if (!server._ssrExternals) {
+ let knownImports: string[] = []
+ const optimizedDeps = server._optimizedDeps
+ if (optimizedDeps) {
+ await optimizedDeps.scanProcessing
+ knownImports = [
+ ...Object.keys(optimizedDeps.metadata.optimized),
+ ...Object.keys(optimizedDeps.metadata.discovered)
+ ]
+ }
+ server._ssrExternals = resolveSSRExternal(config, knownImports)
}
-
- server._ssrExternals ||= resolveSSRExternal(
- config,
- configFileDependencies
- )
return ssrLoadModule(
url,
server,
@@ -434,12 +425,11 @@ export async function createServer(
return server._restartPromise
},
- _optimizeDepsMetadata: null,
+ _optimizedDeps: null,
_ssrExternals: null,
_globImporters: Object.create(null),
_restartPromise: null,
_forceOptimizeOnRestart: false,
- _registerMissingImport: null,
_pendingRequests: new Map()
}
@@ -526,7 +516,7 @@ export async function createServer(
// proxy
const { proxy } = serverConfig
if (proxy) {
- middlewares.use(proxyMiddleware(httpServer, config))
+ middlewares.use(proxyMiddleware(httpServer, proxy, config))
}
// base
@@ -581,39 +571,15 @@ export async function createServer(
// error handler
middlewares.use(errorMiddleware(server, !!middlewareMode))
- const runOptimize = async () => {
- const optimizeDeps = await createOptimizeDepsRun(
- config,
- config.server.force
- )
-
- // Don't await for the optimization to finish, we can start the
- // server right away here
- server._optimizeDepsMetadata = optimizeDeps.metadata
-
- // Run deps optimization in parallel
- const initialProcessingPromise = optimizeDeps
- .run()
- .then((result) => result.commit())
-
- // While running the first optimizeDeps, _registerMissingImport is null
- // so the resolve plugin resolves straight to node_modules during the
- // deps discovery scan phase
- server._registerMissingImport = createMissingImporterRegisterFn(
- server,
- initialProcessingPromise
- )
- }
-
if (!middlewareMode && httpServer) {
let isOptimized = false
- // overwrite listen to run optimizer before server start
+ // overwrite listen to init optimizer before server start
const listen = httpServer.listen.bind(httpServer)
httpServer.listen = (async (port: number, ...args: any[]) => {
if (!isOptimized) {
try {
await container.buildStart({})
- await runOptimize()
+ server._optimizedDeps = createOptimizedDeps(server)
isOptimized = true
} catch (e) {
httpServer.emit('error', e)
@@ -624,7 +590,7 @@ export async function createServer(
}) as any
} else {
await container.buildStart({})
- await runOptimize()
+ server._optimizedDeps = createOptimizedDeps(server)
}
return server
@@ -641,7 +607,7 @@ async function startServer(
}
const options = server.config.server
- const port = inlinePort || options.port || 3000
+ const port = inlinePort ?? options.port ?? 3000
const hostname = resolveHostname(options.host)
const protocol = options.https ? 'https' : 'http'
diff --git a/packages/vite/src/node/server/middlewares/compression.ts b/packages/vite/src/node/server/middlewares/compression.ts
index 7a97044985ac0e..bafae7ef2023c6 100644
--- a/packages/vite/src/node/server/middlewares/compression.ts
+++ b/packages/vite/src/node/server/middlewares/compression.ts
@@ -13,7 +13,7 @@ const noop = () => {}
const mimes = /text|javascript|\/json|xml/i
const threshold = 1024
const level = -1
-const brotli = false
+let brotli = false
const gzip = true
const getChunkSize = (chunk, enc) => (chunk ? Buffer.byteLength(chunk, enc) : 0)
diff --git a/packages/vite/src/node/server/middlewares/indexHtml.ts b/packages/vite/src/node/server/middlewares/indexHtml.ts
index 07b2693c07f995..ca2538bd9507ed 100644
--- a/packages/vite/src/node/server/middlewares/indexHtml.ts
+++ b/packages/vite/src/node/server/middlewares/indexHtml.ts
@@ -1,7 +1,7 @@
import fs from 'fs'
import path from 'path'
import MagicString from 'magic-string'
-import type { AttributeNode, ElementNode } from '@vue/compiler-dom'
+import type { AttributeNode, ElementNode, TextNode } from '@vue/compiler-dom'
import { NodeTypes } from '@vue/compiler-dom'
import type { Connect } from 'types/connect'
import type { IndexHtmlTransformHook } from '../../plugins/html'
@@ -38,7 +38,9 @@ function getHtmlFilename(url: string, server: ViteDevServer) {
if (url.startsWith(FS_PREFIX)) {
return decodeURIComponent(fsPathFromId(url))
} else {
- return decodeURIComponent(path.join(server.config.root, url.slice(1)))
+ return decodeURIComponent(
+ normalizePath(path.join(server.config.root, url.slice(1)))
+ )
}
}
@@ -90,7 +92,7 @@ const processNodeUrl = (
}
const devHtmlHook: IndexHtmlTransformHook = async (
html,
- { path: htmlPath, server, originalUrl }
+ { path: htmlPath, filename, server, originalUrl }
) => {
const { config, moduleGraph } = server!
const base = config.base || '/'
@@ -104,12 +106,17 @@ const devHtmlHook: IndexHtmlTransformHook = async (
const url = filePath.replace(normalizePath(config.root), '')
- const contents = node.children
- .map((child: any) => child.content || '')
- .join('')
+ const contentNode = node.children[0] as TextNode
+
+ const code = contentNode.content
+ const map = new MagicString(html)
+ .snip(contentNode.loc.start.offset, contentNode.loc.end.offset)
+ .generateMap({ hires: true })
+ map.sources = [filename]
+ map.file = filename
// add HTML Proxy to Map
- addToHTMLProxyCache(config, url, inlineModuleIndex, contents)
+ addToHTMLProxyCache(config, url, inlineModuleIndex, { code, map })
// inline js module. convert to src="proxy"
const modulePath = `${
@@ -141,7 +148,7 @@ const devHtmlHook: IndexHtmlTransformHook = async (
if (src) {
processNodeUrl(src, s, config, htmlPath, originalUrl, moduleGraph)
- } else if (isModule) {
+ } else if (isModule && node.children.length) {
addInlineModule(node, 'js')
}
}
diff --git a/packages/vite/src/node/server/middlewares/proxy.ts b/packages/vite/src/node/server/middlewares/proxy.ts
index aa1100f13d5229..97de98a8331a7a 100644
--- a/packages/vite/src/node/server/middlewares/proxy.ts
+++ b/packages/vite/src/node/server/middlewares/proxy.ts
@@ -5,7 +5,7 @@ import { HMR_HEADER } from '../ws'
import type { Connect } from 'types/connect'
import type { HttpProxy } from 'types/http-proxy'
import colors from 'picocolors'
-import type { ResolvedConfig } from '../..'
+import type { CommonServerOptions, ResolvedConfig } from '../..'
const debug = createDebugger('vite:proxy')
@@ -30,10 +30,9 @@ export interface ProxyOptions extends HttpProxy.ServerOptions {
export function proxyMiddleware(
httpServer: http.Server | null,
+ options: NonNullable,
config: ResolvedConfig
): Connect.NextHandleFunction {
- const options = config.server.proxy!
-
// lazy require only when proxy is used
const proxies: Record = {}
diff --git a/packages/vite/src/node/server/middlewares/static.ts b/packages/vite/src/node/server/middlewares/static.ts
index a6623338783cc8..5fb4f7fad2e055 100644
--- a/packages/vite/src/node/server/middlewares/static.ts
+++ b/packages/vite/src/node/server/middlewares/static.ts
@@ -111,7 +111,7 @@ export function serveRawFsMiddleware(
// Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...`
return function viteServeRawFsMiddleware(req, res, next) {
- let url = req.url!
+ let url = decodeURI(req.url!)
// In some cases (e.g. linked monorepos) files outside of root will
// reference assets that are also out of served root. In such cases
// the paths are rewritten to `/@fs/` prefixed paths and must be served by
diff --git a/packages/vite/src/node/server/moduleGraph.ts b/packages/vite/src/node/server/moduleGraph.ts
index 44e76deef98b6f..e470fafb05d8fd 100644
--- a/packages/vite/src/node/server/moduleGraph.ts
+++ b/packages/vite/src/node/server/moduleGraph.ts
@@ -27,7 +27,7 @@ export class ModuleNode {
importers = new Set()
importedModules = new Set()
acceptedHmrDeps = new Set()
- isSelfAccepting = false
+ isSelfAccepting?: boolean
transformResult: TransformResult | null = null
ssrTransformResult: TransformResult | null = null
ssrModule: Record | null = null
diff --git a/packages/vite/src/node/server/pluginContainer.ts b/packages/vite/src/node/server/pluginContainer.ts
index 2aab3e03097c99..5efc2670c0f81a 100644
--- a/packages/vite/src/node/server/pluginContainer.ts
+++ b/packages/vite/src/node/server/pluginContainer.ts
@@ -90,6 +90,10 @@ export interface PluginContainer {
options?: {
skip?: Set
ssr?: boolean
+ /**
+ * @internal
+ */
+ scan?: boolean
}
): Promise
transform(
@@ -212,6 +216,7 @@ export async function createPluginContainer(
class Context implements PluginContext {
meta = minimalContext.meta
ssr = false
+ _scan = false
_activePlugin: Plugin | null
_activeId: string | null = null
_activeCode: string | null = null
@@ -241,7 +246,11 @@ export async function createPluginContainer(
skip = new Set(this._resolveSkips)
skip.add(this._activePlugin)
}
- let out = await container.resolveId(id, importer, { skip, ssr: this.ssr })
+ let out = await container.resolveId(id, importer, {
+ skip,
+ ssr: this.ssr,
+ scan: this._scan
+ })
if (typeof out === 'string') out = { id: out }
return out as ResolvedId | null
}
@@ -433,7 +442,7 @@ export async function createPluginContainer(
? new MagicString(this.originalCode).generateMap({
includeContent: true,
hires: true,
- source: this.filename
+ source: cleanUrl(this.filename)
})
: null
}
@@ -487,8 +496,10 @@ export async function createPluginContainer(
async resolveId(rawId, importer = join(root, 'index.html'), options) {
const skip = options?.skip
const ssr = options?.ssr
+ const scan = !!options?.scan
const ctx = new Context()
ctx.ssr = !!ssr
+ ctx._scan = scan
ctx._resolveSkips = skip
const resolveStart = isDebug ? performance.now() : 0
@@ -505,7 +516,7 @@ export async function createPluginContainer(
ctx as any,
rawId,
importer,
- { ssr }
+ { ssr, scan }
)
if (!result) continue
diff --git a/packages/vite/src/node/server/sourcemap.ts b/packages/vite/src/node/server/sourcemap.ts
index 68684a3c2d6f2a..dc77c4a4714298 100644
--- a/packages/vite/src/node/server/sourcemap.ts
+++ b/packages/vite/src/node/server/sourcemap.ts
@@ -1,8 +1,9 @@
import path from 'path'
import { promises as fs } from 'fs'
import type { Logger } from '../logger'
-import { createDebugger } from '../utils'
+import { createDebugger, normalizePath } from '../utils'
import type { SourceMap } from 'rollup'
+import { maybeVirtualHtmlSet } from '../plugins/html'
const isDebug = !!process.env.DEBUG
const debug = createDebugger('vite:sourcemap', {
@@ -42,6 +43,7 @@ export async function injectSourcesContent(
sourcePath = path.resolve(sourceRoot, sourcePath)
}
return fs.readFile(sourcePath, 'utf-8').catch(() => {
+ if (maybeVirtualHtmlSet.has(normalizePath(sourcePath))) return null
missingSources.push(sourcePath)
return null
})
diff --git a/packages/vite/src/node/server/ws.ts b/packages/vite/src/node/server/ws.ts
index 479fc63daef2b6..6d4e66ec1a22ae 100644
--- a/packages/vite/src/node/server/ws.ts
+++ b/packages/vite/src/node/server/ws.ts
@@ -3,37 +3,99 @@ import type { Server } from 'http'
import { STATUS_CODES } from 'http'
import type { ServerOptions as HttpsServerOptions } from 'https'
import { createServer as createHttpsServer } from 'https'
-import type { ServerOptions } from 'ws'
-import { WebSocketServer as WebSocket } from 'ws'
+import type { ServerOptions, WebSocket as WebSocketRaw } from 'ws'
+import { WebSocketServer as WebSocketServerRaw } from 'ws'
import type { WebSocket as WebSocketTypes } from 'types/ws'
-import type { ErrorPayload, HMRPayload } from 'types/hmrPayload'
+import type { CustomPayload, ErrorPayload, HMRPayload } from 'types/hmrPayload'
+import type { InferCustomEventPayload } from 'types/customEvent'
import type { ResolvedConfig } from '..'
import { isObject } from '../utils'
import type { Socket } from 'net'
+
export const HMR_HEADER = 'vite-hmr'
+export type WebSocketCustomListener = (
+ data: T,
+ client: WebSocketClient
+) => void
+
export interface WebSocketServer {
- on: WebSocketTypes.Server['on']
- off: WebSocketTypes.Server['off']
+ /**
+ * Get all connected clients.
+ */
+ clients: Set
+ /**
+ * Boardcast events to all clients
+ */
send(payload: HMRPayload): void
+ /**
+ * Send custom event
+ */
+ send(event: T, payload?: InferCustomEventPayload): void
+ /**
+ * Disconnect all clients and terminate the server.
+ */
close(): Promise
+ /**
+ * Handle custom event emitted by `import.meta.hot.send`
+ */
+ on: WebSocketTypes.Server['on'] & {
+ (
+ event: T,
+ listener: WebSocketCustomListener>
+ ): void
+ }
+ /**
+ * Unregister event listener.
+ */
+ off: WebSocketTypes.Server['off'] & {
+ (event: string, listener: Function): void
+ }
+}
+
+export interface WebSocketClient {
+ /**
+ * Send event to the client
+ */
+ send(payload: HMRPayload): void
+ /**
+ * Send custom event
+ */
+ send(event: string, payload?: CustomPayload['data']): void
+ /**
+ * The raw WebSocket instance
+ * @advanced
+ */
+ socket: WebSocketTypes
}
+const wsServerEvents = [
+ 'connection',
+ 'error',
+ 'headers',
+ 'listening',
+ 'message'
+]
+
export function createWebSocketServer(
server: Server | null,
config: ResolvedConfig,
httpsOptions?: HttpsServerOptions
): WebSocketServer {
- let wss: WebSocket
+ let wss: WebSocketServerRaw
let httpsServer: Server | undefined = undefined
const hmr = isObject(config.server.hmr) && config.server.hmr
- const wsServer =
- (hmr && hmr.server) ||
- ((!(hmr && hmr.port) || hmr.port !== config.server.port) && server)
+ const hmrServer = hmr && hmr.server
+ const hmrPort = hmr && hmr.port
+ // TODO: the main server port may not have been chosen yet as it may use the next available
+ const portsAreCompatible = !hmrPort || hmrPort === config.server.port
+ const wsServer = hmrServer || (portsAreCompatible && server)
+ const customListeners = new Map>>()
+ const clientsMap = new WeakMap()
if (wsServer) {
- wss = new WebSocket({ noServer: true })
+ wss = new WebSocketServerRaw({ noServer: true })
wsServer.on('upgrade', (req, socket, head) => {
if (req.headers['sec-websocket-protocol'] === HMR_HEADER) {
wss.handleUpgrade(req, socket as Socket, head, (ws) => {
@@ -43,7 +105,7 @@ export function createWebSocketServer(
})
} else {
const websocketServerOptions: ServerOptions = {}
- const port = (hmr && hmr.port) || 24678
+ const port = hmrPort || 24678
const host = (hmr && hmr.host) || undefined
if (httpsOptions) {
// if we're serving the middlewares over https, the ws library doesn't support automatically creating an https server, so we need to do it ourselves
@@ -74,10 +136,22 @@ export function createWebSocketServer(
}
// vite dev server in middleware mode
- wss = new WebSocket(websocketServerOptions)
+ wss = new WebSocketServerRaw(websocketServerOptions)
}
wss.on('connection', (socket) => {
+ socket.on('message', (raw) => {
+ if (!customListeners.size) return
+ let parsed: any
+ try {
+ parsed = JSON.parse(String(raw))
+ } catch {}
+ if (!parsed || parsed.type !== 'custom' || !parsed.event) return
+ const listeners = customListeners.get(parsed.event)
+ if (!listeners?.size) return
+ const client = getSocketClent(socket)
+ listeners.forEach((listener) => listener(parsed.data, client))
+ })
socket.send(JSON.stringify({ type: 'connected' }))
if (bufferedError) {
socket.send(JSON.stringify(bufferedError))
@@ -94,6 +168,30 @@ export function createWebSocketServer(
}
})
+ // Provide a wrapper to the ws client so we can send messages in JSON format
+ // To be consistent with server.ws.send
+ function getSocketClent(socket: WebSocketRaw) {
+ if (!clientsMap.has(socket)) {
+ clientsMap.set(socket, {
+ send: (...args) => {
+ let payload: HMRPayload
+ if (typeof args[0] === 'string') {
+ payload = {
+ type: 'custom',
+ event: args[0],
+ data: args[1]
+ }
+ } else {
+ payload = args[0]
+ }
+ socket.send(JSON.stringify(payload))
+ },
+ socket
+ })
+ }
+ return clientsMap.get(socket)!
+ }
+
// On page reloads, if a file fails to compile and returns 500, the server
// sends the error payload before the client connection is established.
// If we have no open clients, buffer the error and send it to the next
@@ -101,9 +199,39 @@ export function createWebSocketServer(
let bufferedError: ErrorPayload | null = null
return {
- on: wss.on.bind(wss),
- off: wss.off.bind(wss),
- send(payload: HMRPayload) {
+ on: ((event: string, fn: () => void) => {
+ if (wsServerEvents.includes(event)) wss.on(event, fn)
+ else {
+ if (!customListeners.has(event)) {
+ customListeners.set(event, new Set())
+ }
+ customListeners.get(event)!.add(fn)
+ }
+ }) as WebSocketServer['on'],
+ off: ((event: string, fn: () => void) => {
+ if (wsServerEvents.includes(event)) {
+ wss.off(event, fn)
+ } else {
+ customListeners.get(event)?.delete(fn)
+ }
+ }) as WebSocketServer['off'],
+
+ get clients() {
+ return new Set(Array.from(wss.clients).map(getSocketClent))
+ },
+
+ send(...args: any[]) {
+ let payload: HMRPayload
+ if (typeof args[0] === 'string') {
+ payload = {
+ type: 'custom',
+ event: args[0],
+ data: args[1]
+ }
+ } else {
+ payload = args[0]
+ }
+
if (payload.type === 'error' && !wss.clients.size) {
bufferedError = payload
return
diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts
index 4e0f230fd7edfd..8c7859e3850454 100644
--- a/packages/vite/src/node/utils.ts
+++ b/packages/vite/src/node/utils.ts
@@ -83,6 +83,7 @@ export function resolveFrom(
): string {
return resolve.sync(id, {
basedir,
+ paths: [],
extensions: ssr ? ssrExtensions : DEFAULT_EXTENSIONS,
// necessary to work with pnpm
preserveSymlinks: preserveSymlinks || isRunningWithYarnPnp || false
@@ -615,13 +616,16 @@ export function combineSourcemaps(
// hack for parse broken with normalized absolute paths on windows (C:/path/to/something).
// escape them to linux like paths
- sourcemapList.forEach((sourcemap) => {
- sourcemap.sources = sourcemap.sources.map((source) =>
+ // also avoid mutation here to prevent breaking plugin's using cache to generate sourcemaps like vue (see #7442)
+ sourcemapList = sourcemapList.map((sourcemap) => {
+ const newSourcemaps = { ...sourcemap }
+ newSourcemaps.sources = sourcemap.sources.map((source) =>
source ? escapeToLinuxLikePath(source) : null
)
if (sourcemap.sourceRoot) {
- sourcemap.sourceRoot = escapeToLinuxLikePath(sourcemap.sourceRoot)
+ newSourcemaps.sourceRoot = escapeToLinuxLikePath(sourcemap.sourceRoot)
}
+ return newSourcemaps
})
const escapedFilename = escapeToLinuxLikePath(filename)
@@ -729,3 +733,4 @@ export function parseRequest(id: string): Record | null {
}
export const blankReplacer = (match: string) => ' '.repeat(match.length)
+export const stringsRE = /"[^"]*"|'[^']*'|`[^`]*`/g
diff --git a/packages/vite/types/customEvent.d.ts b/packages/vite/types/customEvent.d.ts
index c38a4ac940ff6e..af4db5d14fbe97 100644
--- a/packages/vite/types/customEvent.d.ts
+++ b/packages/vite/types/customEvent.d.ts
@@ -1,5 +1,16 @@
-// See https://stackoverflow.com/a/63549561.
-export type CustomEventName = (T extends `vite:${T}`
- ? never
- : T) &
- (`vite:${T}` extends T ? never : T)
+import type {
+ ErrorPayload,
+ FullReloadPayload,
+ PrunePayload,
+ UpdatePayload
+} from './hmrPayload'
+
+export interface CustomEventMap {
+ 'vite:beforeUpdate': UpdatePayload
+ 'vite:beforePrune': PrunePayload
+ 'vite:beforeFullReload': FullReloadPayload
+ 'vite:error': ErrorPayload
+}
+
+export type InferCustomEventPayload =
+ T extends keyof CustomEventMap ? CustomEventMap[T] : any
diff --git a/packages/vite/types/hot.d.ts b/packages/vite/types/hot.d.ts
new file mode 100644
index 00000000000000..f06846ff59d530
--- /dev/null
+++ b/packages/vite/types/hot.d.ts
@@ -0,0 +1,25 @@
+import type { InferCustomEventPayload } from './customEvent'
+
+export interface ViteHotContext {
+ readonly data: any
+
+ accept(): void
+ accept(cb: (mod: any) => void): void
+ accept(dep: string, cb: (mod: any) => void): void
+ accept(deps: readonly string[], cb: (mods: any[]) => void): void
+
+ /**
+ * @deprecated
+ */
+ acceptDeps(): never
+
+ dispose(cb: (data: any) => void): void
+ decline(): void
+ invalidate(): void
+
+ on(
+ event: T,
+ cb: (payload: InferCustomEventPayload) => void
+ ): void
+ send(event: T, data?: InferCustomEventPayload): void
+}
diff --git a/packages/vite/types/importMeta.d.ts b/packages/vite/types/importMeta.d.ts
index 56b82125381e20..9b57fd120a7ba9 100644
--- a/packages/vite/types/importMeta.d.ts
+++ b/packages/vite/types/importMeta.d.ts
@@ -20,46 +20,7 @@ interface GlobOptions {
interface ImportMeta {
url: string
- readonly hot?: {
- readonly data: any
-
- accept(): void
- accept(cb: (mod: any) => void): void
- accept(dep: string, cb: (mod: any) => void): void
- accept(deps: readonly string[], cb: (mods: any[]) => void): void
-
- /**
- * @deprecated
- */
- acceptDeps(): never
-
- dispose(cb: (data: any) => void): void
- decline(): void
- invalidate(): void
-
- on: {
- (
- event: 'vite:beforeUpdate',
- cb: (payload: import('./hmrPayload').UpdatePayload) => void
- ): void
- (
- event: 'vite:beforePrune',
- cb: (payload: import('./hmrPayload').PrunePayload) => void
- ): void
- (
- event: 'vite:beforeFullReload',
- cb: (payload: import('./hmrPayload').FullReloadPayload) => void
- ): void
- (
- event: 'vite:error',
- cb: (payload: import('./hmrPayload').ErrorPayload) => void
- ): void
- (
- event: import('./customEvent').CustomEventName,
- cb: (data: any) => void
- ): void
- }
- }
+ readonly hot?: import('./hot').ViteHotContext
readonly env: ImportMetaEnv
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0a9145995c4bcf..a54c2eadfcfff2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4,77 +4,79 @@ overrides:
vite: workspace:*
'@vitejs/plugin-vue': workspace:*
+packageExtensionsChecksum: 696422bac84dd936748019990f84746e
+
importers:
.:
specifiers:
- '@microsoft/api-extractor': ^7.19.5
+ '@microsoft/api-extractor': ^7.20.0
'@types/fs-extra': ^9.0.13
'@types/jest': ^27.4.1
'@types/node': ^16.11.26
'@types/prompts': ^2.0.14
'@types/semver': ^7.3.9
- '@typescript-eslint/eslint-plugin': ^5.16.0
- '@typescript-eslint/parser': ^5.16.0
+ '@typescript-eslint/eslint-plugin': ^5.17.0
+ '@typescript-eslint/parser': ^5.17.0
conventional-changelog-cli: ^2.2.2
cross-env: ^7.0.3
esbuild: ^0.14.27
- eslint: ^8.11.0
+ eslint: ^8.12.0
eslint-define-config: ^1.3.0
eslint-plugin-node: ^11.1.0
execa: ^5.1.1
fs-extra: ^10.0.1
jest: ^27.5.1
lint-staged: ^12.3.7
- minimist: ^1.2.5
+ minimist: ^1.2.6
node-fetch: ^2.6.6
npm-run-all: ^4.1.5
picocolors: ^1.0.0
- playwright-chromium: ^1.20.0
- prettier: 2.6.0
+ playwright-chromium: ^1.20.2
+ prettier: 2.6.2
prompts: ^2.4.2
rimraf: ^3.0.2
rollup: ^2.59.0
semver: ^7.3.5
simple-git-hooks: ^2.7.0
sirv: ^2.0.2
- ts-jest: ^27.1.3
+ ts-jest: ^27.1.4
ts-node: ^10.4.0
typescript: ~4.5.4
vite: workspace:*
vitepress: ^0.22.3
devDependencies:
- '@microsoft/api-extractor': 7.19.5
+ '@microsoft/api-extractor': 7.20.0
'@types/fs-extra': 9.0.13
'@types/jest': 27.4.1
'@types/node': 16.11.26
'@types/prompts': 2.0.14
'@types/semver': 7.3.9
- '@typescript-eslint/eslint-plugin': 5.16.0_1324a086488ab25887f801dfb12f1aba
- '@typescript-eslint/parser': 5.16.0_eslint@8.11.0+typescript@4.5.4
+ '@typescript-eslint/eslint-plugin': 5.17.0_d58f0eed9ebf32fdeceb6a8716e9bcf1
+ '@typescript-eslint/parser': 5.17.0_eslint@8.12.0+typescript@4.5.4
conventional-changelog-cli: 2.2.2
cross-env: 7.0.3
esbuild: 0.14.27
- eslint: 8.11.0
+ eslint: 8.12.0
eslint-define-config: 1.3.0
- eslint-plugin-node: 11.1.0_eslint@8.11.0
+ eslint-plugin-node: 11.1.0_eslint@8.12.0
execa: 5.1.1
fs-extra: 10.0.1
jest: 27.5.1_ts-node@10.4.0
lint-staged: 12.3.7
- minimist: 1.2.5
+ minimist: 1.2.6
node-fetch: 2.6.6
npm-run-all: 4.1.5
picocolors: 1.0.0
- playwright-chromium: 1.20.0
- prettier: 2.6.0
+ playwright-chromium: 1.20.2
+ prettier: 2.6.2
prompts: 2.4.2
rimraf: 3.0.2
rollup: 2.62.0
semver: 7.3.5
simple-git-hooks: 2.7.0
sirv: 2.0.2
- ts-jest: 27.1.3_4dfe14e0e8266437469ae0475a5c09ac
+ ts-jest: 27.1.4_4dfe14e0e8266437469ae0475a5c09ac
ts-node: 10.4.0_44ef5af6cbbc24239b4e70b5c7b0d7a6
typescript: 4.5.4
vite: link:packages/vite
@@ -83,17 +85,19 @@ importers:
packages/create-vite:
specifiers:
kolorist: ^1.5.1
- minimist: ^1.2.5
+ minimist: ^1.2.6
prompts: ^2.4.2
dependencies:
kolorist: 1.5.1
- minimist: 1.2.5
+ minimist: 1.2.6
prompts: 2.4.2
packages/playground:
specifiers:
+ convert-source-map: ^1.8.0
css-color-names: ^1.0.1
devDependencies:
+ convert-source-map: 1.8.0
css-color-names: 1.0.1
packages/playground/alias:
@@ -152,13 +156,11 @@ importers:
packages/playground/css-sourcemap:
specifiers:
- convert-source-map: ^1.8.0
less: ^4.1.2
magic-string: ^0.25.7
sass: ^1.43.4
stylus: ^0.55.0
devDependencies:
- convert-source-map: 1.8.0
less: 4.1.2
magic-string: 0.25.7
sass: 1.45.1
@@ -223,6 +225,9 @@ importers:
packages/playground/html:
specifiers: {}
+ packages/playground/js-sourcemap:
+ specifiers: {}
+
packages/playground/json:
specifiers:
json-module: file:./json-module
@@ -456,6 +461,8 @@ importers:
'@babel/runtime': ^7.16.0
es5-ext: 0.10.53
normalize.css: ^8.0.1
+ require-pkg-with-browser-and-module-field: link:./require-pkg-with-browser-and-module-field
+ require-pkg-with-esm-entries: link:./require-pkg-with-esm-entries
resolve-browser-field: link:./browser-field
resolve-custom-condition: link:./custom-condition
resolve-custom-main-field: link:./custom-main-field
@@ -466,6 +473,8 @@ importers:
'@babel/runtime': 7.16.5
es5-ext: 0.10.53
normalize.css: 8.0.1
+ require-pkg-with-browser-and-module-field: link:require-pkg-with-browser-and-module-field
+ require-pkg-with-esm-entries: link:require-pkg-with-esm-entries
resolve-browser-field: link:browser-field
resolve-custom-condition: link:custom-condition
resolve-custom-main-field: link:custom-main-field
@@ -497,6 +506,18 @@ importers:
packages/playground/resolve/inline-package:
specifiers: {}
+ packages/playground/resolve/require-pkg-with-browser-and-module-field:
+ specifiers:
+ bignumber.js: 9.0.2
+ dependencies:
+ bignumber.js: 9.0.2
+
+ packages/playground/resolve/require-pkg-with-esm-entries:
+ specifiers:
+ callbag-from-event: 1.3.0
+ dependencies:
+ callbag-from-event: 1.3.0
+
packages/playground/ssr-deps:
specifiers:
bcrypt: ^5.0.1
@@ -653,6 +674,12 @@ importers:
devDependencies:
'@vitejs/plugin-vue': link:../../plugin-vue
+ packages/playground/tailwind-sourcemap:
+ specifiers:
+ tailwindcss: ^3.0.23
+ dependencies:
+ tailwindcss: 3.0.23_ts-node@10.4.0
+
packages/playground/tsconfig-json:
specifiers: {}
@@ -703,7 +730,6 @@ importers:
packages/playground/vue-sourcemap:
specifiers:
'@vitejs/plugin-vue': workspace:*
- convert-source-map: ^1.8.0
less: ^4.1.2
sass: ^1.43.4
vue: ^3.2.31
@@ -711,7 +737,6 @@ importers:
vue: 3.2.31
devDependencies:
'@vitejs/plugin-vue': link:../../plugin-vue
- convert-source-map: 1.8.0
less: 4.1.2
sass: 1.45.1
@@ -746,7 +771,7 @@ importers:
'@babel/plugin-transform-react-jsx-self': ^7.16.7
'@babel/plugin-transform-react-jsx-source': ^7.16.7
'@rollup/pluginutils': ^4.2.0
- react-refresh: ^0.11.0
+ react-refresh: ^0.12.0
resolve: ^1.22.0
dependencies:
'@babel/core': 7.17.8
@@ -755,7 +780,7 @@ importers:
'@babel/plugin-transform-react-jsx-self': 7.16.7_@babel+core@7.17.8
'@babel/plugin-transform-react-jsx-source': 7.16.7_@babel+core@7.17.8
'@rollup/pluginutils': 4.2.0
- react-refresh: 0.11.0
+ react-refresh: 0.12.0
resolve: 1.22.0
packages/plugin-vue:
@@ -801,7 +826,7 @@ importers:
'@babel/types': ^7.17.0
'@jridgewell/trace-mapping': ^0.3.4
'@rollup/plugin-alias': ^3.1.9
- '@rollup/plugin-commonjs': ^21.0.2
+ '@rollup/plugin-commonjs': ^21.0.3
'@rollup/plugin-dynamic-import-vars': ^1.4.2
'@rollup/plugin-json': ^4.1.0
'@rollup/plugin-node-resolve': 13.1.3
@@ -818,7 +843,7 @@ importers:
'@types/node': ^16.11.26
'@types/resolve': ^1.20.1
'@types/sass': ~1.43.1
- '@types/stylus': ^0.48.36
+ '@types/stylus': ^0.48.37
'@types/ws': ^8.5.3
'@vue/compiler-dom': ^3.2.31
acorn: ^8.7.0
@@ -832,7 +857,7 @@ importers:
debug: ^4.3.4
dotenv: ^14.3.2
dotenv-expand: ^5.1.0
- es-module-lexer: ^0.10.4
+ es-module-lexer: ^0.10.5
esbuild: ^0.14.27
estree-walker: ^2.0.2
etag: ^1.8.1
@@ -842,16 +867,16 @@ importers:
json5: ^2.2.1
launch-editor-middleware: ^2.3.0
magic-string: ^0.26.1
- micromatch: ^4.0.4
+ micromatch: ^4.0.5
mrmime: ^1.0.0
- node-forge: ^1.3.0
+ node-forge: ^1.3.1
okie: ^1.0.1
open: ^8.4.0
periscopic: ^2.0.3
picocolors: ^1.0.0
postcss: ^8.4.12
- postcss-import: ^14.0.2
- postcss-load-config: ^3.1.3
+ postcss-import: ^14.1.0
+ postcss-load-config: ^3.1.4
postcss-modules: ^4.3.1
resolve: ^1.22.0
resolve.exports: ^1.1.0
@@ -862,7 +887,7 @@ importers:
source-map-support: ^0.5.21
strip-ansi: ^6.0.1
terser: ^5.12.1
- tsconfck: ^1.2.0
+ tsconfck: ^1.2.2
tslib: ^2.3.1
types: link:./types
ws: ^8.5.0
@@ -879,7 +904,7 @@ importers:
'@babel/types': 7.17.0
'@jridgewell/trace-mapping': 0.3.4
'@rollup/plugin-alias': 3.1.9_rollup@2.62.0
- '@rollup/plugin-commonjs': 21.0.2_rollup@2.62.0
+ '@rollup/plugin-commonjs': 21.0.3_rollup@2.62.0
'@rollup/plugin-dynamic-import-vars': 1.4.2_rollup@2.62.0
'@rollup/plugin-json': 4.1.0_rollup@2.62.0
'@rollup/plugin-node-resolve': 13.1.3_rollup@2.62.0
@@ -896,7 +921,7 @@ importers:
'@types/node': 16.11.26
'@types/resolve': 1.20.1
'@types/sass': 1.43.1
- '@types/stylus': 0.48.36
+ '@types/stylus': 0.48.37
'@types/ws': 8.5.3
'@vue/compiler-dom': 3.2.31
acorn: 8.7.0
@@ -910,7 +935,7 @@ importers:
debug: 4.3.4
dotenv: 14.3.2
dotenv-expand: 5.1.0
- es-module-lexer: 0.10.4
+ es-module-lexer: 0.10.5
estree-walker: 2.0.2
etag: 1.8.1
fast-glob: 3.2.11
@@ -918,15 +943,15 @@ importers:
json5: 2.2.1
launch-editor-middleware: 2.3.0
magic-string: 0.26.1
- micromatch: 4.0.4
+ micromatch: 4.0.5
mrmime: 1.0.0
- node-forge: 1.3.0
+ node-forge: 1.3.1
okie: 1.0.1
open: 8.4.0
periscopic: 2.0.3
picocolors: 1.0.0
- postcss-import: 14.0.2_postcss@8.4.12
- postcss-load-config: 3.1.3_ts-node@10.4.0
+ postcss-import: 14.1.0_postcss@8.4.12
+ postcss-load-config: 3.1.4_postcss@8.4.12+ts-node@10.4.0
postcss-modules: 4.3.1_postcss@8.4.12
resolve.exports: 1.1.0
rollup-plugin-license: 2.6.1_rollup@2.62.0
@@ -935,7 +960,7 @@ importers:
source-map-support: 0.5.21
strip-ansi: 6.0.1
terser: 5.12.1
- tsconfck: 1.2.0_typescript@4.5.4
+ tsconfck: 1.2.2_typescript@4.5.4
tslib: 2.3.1
types: link:types
ws: 8.5.0
@@ -1104,7 +1129,7 @@ packages:
convert-source-map: 1.8.0
debug: 4.3.4
gensync: 1.0.0-beta.2
- json5: 2.2.0
+ json5: 2.2.1
semver: 6.3.0
transitivePeerDependencies:
- supports-color
@@ -2157,17 +2182,6 @@ packages:
- supports-color
dev: true
- /@jest/types/27.4.2:
- resolution: {integrity: sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==}
- engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
- dependencies:
- '@types/istanbul-lib-coverage': 2.0.4
- '@types/istanbul-reports': 3.0.1
- '@types/node': 16.11.26
- '@types/yargs': 16.0.4
- chalk: 4.1.2
- dev: true
-
/@jest/types/27.5.1:
resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
@@ -2209,19 +2223,19 @@ packages:
- supports-color
dev: false
- /@microsoft/api-extractor-model/7.15.4:
- resolution: {integrity: sha512-9bIXQKKQr5jAH1c9atXrukr4ua30fhqxMwWIOOjEnexPBPu3nhy9lC4/GpE0kPUp1Al3wSXgFnOEGzEH+HFz+w==}
+ /@microsoft/api-extractor-model/7.16.0:
+ resolution: {integrity: sha512-0FOrbNIny8mzBrzQnSIkEjAXk0JMSnPmWYxt3ZDTPVg9S8xIPzB6lfgTg9+Mimu0RKCpGKBpd+v2WcR5vGzyUQ==}
dependencies:
'@microsoft/tsdoc': 0.13.2
'@microsoft/tsdoc-config': 0.15.2
'@rushstack/node-core-library': 3.45.1
dev: true
- /@microsoft/api-extractor/7.19.5:
- resolution: {integrity: sha512-ra5r8P7PocOpemrZRccI3Tf1+wukI0gT6ncRB448QSxSYlmqKuvez95YUSYPwHIN/ztKL0cn5PfMOauU1lZfGQ==}
+ /@microsoft/api-extractor/7.20.0:
+ resolution: {integrity: sha512-WKAu5JpkRXWKL3AyxmFXuwNNPpBlsAefwZIDl8M5mhEqRji4w+gexb0pku3Waa0flm3vm0Cwpm+kGYYJ4/gzAA==}
hasBin: true
dependencies:
- '@microsoft/api-extractor-model': 7.15.4
+ '@microsoft/api-extractor-model': 7.16.0
'@microsoft/tsdoc': 0.13.2
'@microsoft/tsdoc-config': 0.15.2
'@rushstack/node-core-library': 3.45.1
@@ -2317,8 +2331,8 @@ packages:
slash: 3.0.0
dev: true
- /@rollup/plugin-commonjs/21.0.2_rollup@2.62.0:
- resolution: {integrity: sha512-d/OmjaLVO4j/aQX69bwpWPpbvI3TJkQuxoAk7BH8ew1PyoMBLTOuvJTjzG8oEoW7drIIqB0KCJtfFLu/2GClWg==}
+ /@rollup/plugin-commonjs/21.0.3_rollup@2.62.0:
+ resolution: {integrity: sha512-ThGfwyvcLc6cfP/MWxA5ACF+LZCvsuhUq7V5134Az1oQWsiC7lNpLT4mJI86WQunK7BYmpUiHmMk2Op6OAHs0g==}
engines: {node: '>= 8.0.0'}
peerDependencies:
rollup: ^2.38.3
@@ -2660,8 +2674,8 @@ packages:
resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==}
dev: true
- /@types/stylus/0.48.36:
- resolution: {integrity: sha512-7klEq45BUE8ZJWkYWy1E442DcCs0wi0FkFY1Tjr6EJ7edL77t9w/QmOwlkFumBMqHlatDBtrA2xgfRrGqkUkzg==}
+ /@types/stylus/0.48.37:
+ resolution: {integrity: sha512-IkLnS/GzdDK3rgAmQwLr8LqPvUMa43SHlCnXqsfXNukwaIpiXBNgSHil3ro8aemhF4k4ZiMoa4URE7mwBHPJnQ==}
dependencies:
'@types/node': 16.11.26
dev: true
@@ -2690,8 +2704,8 @@ packages:
dev: true
optional: true
- /@typescript-eslint/eslint-plugin/5.16.0_1324a086488ab25887f801dfb12f1aba:
- resolution: {integrity: sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw==}
+ /@typescript-eslint/eslint-plugin/5.17.0_d58f0eed9ebf32fdeceb6a8716e9bcf1:
+ resolution: {integrity: sha512-qVstvQilEd89HJk3qcbKt/zZrfBZ+9h2ynpAGlWjWiizA7m/MtLT9RoX6gjtpE500vfIg8jogAkDzdCxbsFASQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
'@typescript-eslint/parser': ^5.0.0
@@ -2701,12 +2715,12 @@ packages:
typescript:
optional: true
dependencies:
- '@typescript-eslint/parser': 5.16.0_eslint@8.11.0+typescript@4.5.4
- '@typescript-eslint/scope-manager': 5.16.0
- '@typescript-eslint/type-utils': 5.16.0_eslint@8.11.0+typescript@4.5.4
- '@typescript-eslint/utils': 5.16.0_eslint@8.11.0+typescript@4.5.4
+ '@typescript-eslint/parser': 5.17.0_eslint@8.12.0+typescript@4.5.4
+ '@typescript-eslint/scope-manager': 5.17.0
+ '@typescript-eslint/type-utils': 5.17.0_eslint@8.12.0+typescript@4.5.4
+ '@typescript-eslint/utils': 5.17.0_eslint@8.12.0+typescript@4.5.4
debug: 4.3.4
- eslint: 8.11.0
+ eslint: 8.12.0
functional-red-black-tree: 1.0.1
ignore: 5.2.0
regexpp: 3.2.0
@@ -2717,8 +2731,8 @@ packages:
- supports-color
dev: true
- /@typescript-eslint/parser/5.16.0_eslint@8.11.0+typescript@4.5.4:
- resolution: {integrity: sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA==}
+ /@typescript-eslint/parser/5.17.0_eslint@8.12.0+typescript@4.5.4:
+ resolution: {integrity: sha512-aRzW9Jg5Rlj2t2/crzhA2f23SIYFlF9mchGudyP0uiD6SenIxzKoLjwzHbafgHn39dNV/TV7xwQkLfFTZlJ4ig==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -2727,26 +2741,26 @@ packages:
typescript:
optional: true
dependencies:
- '@typescript-eslint/scope-manager': 5.16.0
- '@typescript-eslint/types': 5.16.0
- '@typescript-eslint/typescript-estree': 5.16.0_typescript@4.5.4
+ '@typescript-eslint/scope-manager': 5.17.0
+ '@typescript-eslint/types': 5.17.0
+ '@typescript-eslint/typescript-estree': 5.17.0_typescript@4.5.4
debug: 4.3.4
- eslint: 8.11.0
+ eslint: 8.12.0
typescript: 4.5.4
transitivePeerDependencies:
- supports-color
dev: true
- /@typescript-eslint/scope-manager/5.16.0:
- resolution: {integrity: sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ==}
+ /@typescript-eslint/scope-manager/5.17.0:
+ resolution: {integrity: sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
- '@typescript-eslint/types': 5.16.0
- '@typescript-eslint/visitor-keys': 5.16.0
+ '@typescript-eslint/types': 5.17.0
+ '@typescript-eslint/visitor-keys': 5.17.0
dev: true
- /@typescript-eslint/type-utils/5.16.0_eslint@8.11.0+typescript@4.5.4:
- resolution: {integrity: sha512-SKygICv54CCRl1Vq5ewwQUJV/8padIWvPgCxlWPGO/OgQLCijY9G7lDu6H+mqfQtbzDNlVjzVWQmeqbLMBLEwQ==}
+ /@typescript-eslint/type-utils/5.17.0_eslint@8.12.0+typescript@4.5.4:
+ resolution: {integrity: sha512-3hU0RynUIlEuqMJA7dragb0/75gZmwNwFf/QJokWzPehTZousP/MNifVSgjxNcDCkM5HI2K22TjQWUmmHUINSg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '*'
@@ -2755,22 +2769,22 @@ packages:
typescript:
optional: true
dependencies:
- '@typescript-eslint/utils': 5.16.0_eslint@8.11.0+typescript@4.5.4
+ '@typescript-eslint/utils': 5.17.0_eslint@8.12.0+typescript@4.5.4
debug: 4.3.4
- eslint: 8.11.0
+ eslint: 8.12.0
tsutils: 3.21.0_typescript@4.5.4
typescript: 4.5.4
transitivePeerDependencies:
- supports-color
dev: true
- /@typescript-eslint/types/5.16.0:
- resolution: {integrity: sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g==}
+ /@typescript-eslint/types/5.17.0:
+ resolution: {integrity: sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
- /@typescript-eslint/typescript-estree/5.16.0_typescript@4.5.4:
- resolution: {integrity: sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ==}
+ /@typescript-eslint/typescript-estree/5.17.0_typescript@4.5.4:
+ resolution: {integrity: sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
typescript: '*'
@@ -2778,8 +2792,8 @@ packages:
typescript:
optional: true
dependencies:
- '@typescript-eslint/types': 5.16.0
- '@typescript-eslint/visitor-keys': 5.16.0
+ '@typescript-eslint/types': 5.17.0
+ '@typescript-eslint/visitor-keys': 5.17.0
debug: 4.3.4
globby: 11.0.4
is-glob: 4.0.3
@@ -2790,29 +2804,29 @@ packages:
- supports-color
dev: true
- /@typescript-eslint/utils/5.16.0_eslint@8.11.0+typescript@4.5.4:
- resolution: {integrity: sha512-iYej2ER6AwmejLWMWzJIHy3nPJeGDuCqf8Jnb+jAQVoPpmWzwQOfa9hWVB8GIQE5gsCv/rfN4T+AYb/V06WseQ==}
+ /@typescript-eslint/utils/5.17.0_eslint@8.12.0+typescript@4.5.4:
+ resolution: {integrity: sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
'@types/json-schema': 7.0.9
- '@typescript-eslint/scope-manager': 5.16.0
- '@typescript-eslint/types': 5.16.0
- '@typescript-eslint/typescript-estree': 5.16.0_typescript@4.5.4
- eslint: 8.11.0
+ '@typescript-eslint/scope-manager': 5.17.0
+ '@typescript-eslint/types': 5.17.0
+ '@typescript-eslint/typescript-estree': 5.17.0_typescript@4.5.4
+ eslint: 8.12.0
eslint-scope: 5.1.1
- eslint-utils: 3.0.0_eslint@8.11.0
+ eslint-utils: 3.0.0_eslint@8.12.0
transitivePeerDependencies:
- supports-color
- typescript
dev: true
- /@typescript-eslint/visitor-keys/5.16.0:
- resolution: {integrity: sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g==}
+ /@typescript-eslint/visitor-keys/5.17.0:
+ resolution: {integrity: sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
- '@typescript-eslint/types': 5.16.0
+ '@typescript-eslint/types': 5.17.0
eslint-visitor-keys: 3.3.0
dev: true
@@ -3067,7 +3081,7 @@ packages:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
dependencies:
- debug: 4.3.3
+ debug: 4.3.4
transitivePeerDependencies:
- supports-color
@@ -3150,7 +3164,7 @@ packages:
engines: {node: '>= 8'}
dependencies:
normalize-path: 3.0.0
- picomatch: 2.3.0
+ picomatch: 2.3.1
/aproba/2.0.0:
resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
@@ -3253,7 +3267,7 @@ packages:
/axios/0.24.0:
resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==}
dependencies:
- follow-redirects: 1.14.6
+ follow-redirects: 1.14.6_debug@4.3.4
transitivePeerDependencies:
- debug
dev: false
@@ -3365,6 +3379,10 @@ packages:
- supports-color
dev: false
+ /bignumber.js/9.0.2:
+ resolution: {integrity: sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==}
+ dev: false
+
/binary-extensions/2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@@ -3466,6 +3484,16 @@ packages:
get-intrinsic: 1.1.1
dev: true
+ /callbag-from-event/1.3.0:
+ resolution: {integrity: sha512-cAu82hKKFmMtKTmd50p/nlMfs1oKz+PGUZmmwhbzPbw4YtjNgTKg6pXjpcQprhBQdrqg/v8pHcAS8Qs6X7r8fw==}
+ dependencies:
+ callbag: 1.5.0
+ dev: false
+
+ /callbag/1.5.0:
+ resolution: {integrity: sha512-PH3id0HEb/cNS+BehYlF4Z5wzjKAIUao6ab2hWtMs2bi6aW+0PXl0jymqwnFyT2cQO2h30ggUgpQlmzOpAIKNg==}
+ dev: false
+
/callsites/3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@@ -3549,7 +3577,6 @@ packages:
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.2
- dev: true
/chownr/2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
@@ -4165,7 +4192,6 @@ packages:
optional: true
dependencies:
ms: 2.1.2
- dev: true
/debug/4.3.4_supports-color@9.2.1:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
@@ -4425,8 +4451,8 @@ packages:
unbox-primitive: 1.0.1
dev: true
- /es-module-lexer/0.10.4:
- resolution: {integrity: sha512-n5bOGUnrmuCKyMkmHNtC1ObnUx8AgFcKWe2mbxb6jYzuK81W0Rk3Z//sCoGJuxWzos8R2w48TemGIFqZsTY6YA==}
+ /es-module-lexer/0.10.5:
+ resolution: {integrity: sha512-+7IwY/kiGAacQfY+YBhKMvEmyAJnw5grTUgjG85Pe7vcUI/6b7pZjZG8nQ7+48YhzEAEqrEgD2dCz/JIK+AYvw==}
dev: true
/es-to-primitive/1.2.1:
@@ -4688,25 +4714,25 @@ packages:
engines: {node: '>= 16.9.0', npm: '>= 7.0.0', pnpm: '>= 6.32.2'}
dev: true
- /eslint-plugin-es/3.0.1_eslint@8.11.0:
+ /eslint-plugin-es/3.0.1_eslint@8.12.0:
resolution: {integrity: sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==}
engines: {node: '>=8.10.0'}
peerDependencies:
eslint: '>=4.19.1'
dependencies:
- eslint: 8.11.0
+ eslint: 8.12.0
eslint-utils: 2.1.0
regexpp: 3.2.0
dev: true
- /eslint-plugin-node/11.1.0_eslint@8.11.0:
+ /eslint-plugin-node/11.1.0_eslint@8.12.0:
resolution: {integrity: sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==}
engines: {node: '>=8.10.0'}
peerDependencies:
eslint: '>=5.16.0'
dependencies:
- eslint: 8.11.0
- eslint-plugin-es: 3.0.1_eslint@8.11.0
+ eslint: 8.12.0
+ eslint-plugin-es: 3.0.1_eslint@8.12.0
eslint-utils: 2.1.0
ignore: 5.2.0
minimatch: 3.0.4
@@ -4737,13 +4763,13 @@ packages:
eslint-visitor-keys: 1.3.0
dev: true
- /eslint-utils/3.0.0_eslint@8.11.0:
+ /eslint-utils/3.0.0_eslint@8.12.0:
resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
peerDependencies:
eslint: '>=5'
dependencies:
- eslint: 8.11.0
+ eslint: 8.12.0
eslint-visitor-keys: 2.1.0
dev: true
@@ -4762,8 +4788,8 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
- /eslint/8.11.0:
- resolution: {integrity: sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==}
+ /eslint/8.12.0:
+ resolution: {integrity: sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
@@ -4772,11 +4798,11 @@ packages:
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.3
- debug: 4.3.3
+ debug: 4.3.4
doctrine: 3.0.0
escape-string-regexp: 4.0.0
eslint-scope: 7.1.1
- eslint-utils: 3.0.0_eslint@8.11.0
+ eslint-utils: 3.0.0_eslint@8.12.0
eslint-visitor-keys: 3.3.0
espree: 9.3.1
esquery: 1.4.0
@@ -5064,7 +5090,7 @@ packages:
resolution: {integrity: sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==}
dev: true
- /follow-redirects/1.14.6:
+ /follow-redirects/1.14.6_debug@4.3.4:
resolution: {integrity: sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==}
engines: {node: '>=4.0'}
peerDependencies:
@@ -5072,6 +5098,8 @@ packages:
peerDependenciesMeta:
debug:
optional: true
+ dependencies:
+ debug: 4.3.4
/form-data/3.0.1:
resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
@@ -5326,7 +5354,7 @@ packages:
engines: {node: '>=0.4.7'}
hasBin: true
dependencies:
- minimist: 1.2.5
+ minimist: 1.2.6
neo-async: 2.6.2
source-map: 0.6.1
wordwrap: 1.0.0
@@ -5472,7 +5500,7 @@ packages:
engines: {node: '>=8.0.0'}
dependencies:
eventemitter3: 4.0.7
- follow-redirects: 1.14.6
+ follow-redirects: 1.14.6_debug@4.3.4
requires-port: 1.0.0
transitivePeerDependencies:
- debug
@@ -5483,7 +5511,7 @@ packages:
engines: {node: '>= 6'}
dependencies:
agent-base: 6.0.2
- debug: 4.3.3
+ debug: 4.3.4
transitivePeerDependencies:
- supports-color
@@ -6282,18 +6310,6 @@ packages:
- supports-color
dev: true
- /jest-util/27.4.2:
- resolution: {integrity: sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==}
- engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
- dependencies:
- '@jest/types': 27.4.2
- '@types/node': 16.11.26
- chalk: 4.1.2
- ci-info: 3.3.0
- graceful-fs: 4.2.9
- picomatch: 2.3.0
- dev: true
-
/jest-util/27.5.1:
resolution: {integrity: sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
@@ -6463,6 +6479,7 @@ packages:
hasBin: true
dependencies:
minimist: 1.2.5
+ dev: false
/json5/2.2.1:
resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==}
@@ -6569,6 +6586,11 @@ packages:
resolution: {integrity: sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==}
engines: {node: '>=10'}
+ /lilconfig/2.0.5:
+ resolution: {integrity: sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==}
+ engines: {node: '>=10'}
+ dev: true
+
/lines-and-columns/1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
@@ -6812,6 +6834,14 @@ packages:
braces: 3.0.2
picomatch: 2.3.0
+ /micromatch/4.0.5:
+ resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ braces: 3.0.2
+ picomatch: 2.3.1
+ dev: true
+
/mime-db/1.46.0:
resolution: {integrity: sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==}
engines: {node: '>= 0.6'}
@@ -6925,6 +6955,10 @@ packages:
/minimist/1.2.5:
resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==}
+ dev: false
+
+ /minimist/1.2.6:
+ resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==}
/minipass/3.1.6:
resolution: {integrity: sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==}
@@ -7054,8 +7088,8 @@ packages:
engines: {node: '>= 6.0.0'}
dev: true
- /node-forge/1.3.0:
- resolution: {integrity: sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==}
+ /node-forge/1.3.1:
+ resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
engines: {node: '>= 6.13.0'}
dev: true
@@ -7399,6 +7433,10 @@ packages:
resolution: {integrity: sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==}
engines: {node: '>=8.6'}
+ /picomatch/2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
/pidtree/0.3.1:
resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==}
engines: {node: '>=0.10'}
@@ -7446,21 +7484,21 @@ packages:
find-up: 4.1.0
dev: true
- /playwright-chromium/1.20.0:
- resolution: {integrity: sha512-5qyHaW2kFguX4eAne2MgS7AxZBfQ+hN2X0t5SD5mxOTAgwciEAhMNc06o9NxILnRcmF8QSXGg19OSb8VMUBLzg==}
+ /playwright-chromium/1.20.2:
+ resolution: {integrity: sha512-KsiPLRC1v56qLWqjzeEoDZNVW/eFrP5ad0PFQAa74u5EwnnId89LgOHEZFy487tt3xJdv3Ayyfdn8zwsUpS3Qg==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
dependencies:
- playwright-core: 1.20.0
+ playwright-core: 1.20.2
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
dev: true
- /playwright-core/1.20.0:
- resolution: {integrity: sha512-d25IRcdooS278Cijlp8J8A5fLQZ+/aY3dKRJvgX5yjXA69N0huIUdnh3xXSgn+LsQ9DCNmB7Ngof3eY630jgdA==}
+ /playwright-core/1.20.2:
+ resolution: {integrity: sha512-iV6+HftSPalynkq0CYJala1vaTOq7+gU9BRfKCdM9bAxNq/lFLrwbluug2Wt5OoUwbMABcnTThIEm3/qUhCdJQ==}
engines: {node: '>=12'}
hasBin: true
dependencies:
@@ -7498,8 +7536,8 @@ packages:
engines: {node: '>=12.13.0'}
dev: true
- /postcss-import/14.0.2_postcss@8.4.12:
- resolution: {integrity: sha512-BJ2pVK4KhUyMcqjuKs9RijV5tatNzNa73e/32aBVE/ejYPe37iH+6vAu9WvqUkB5OAYgLHzbSvzHnorybJCm9g==}
+ /postcss-import/14.1.0_postcss@8.4.12:
+ resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==}
engines: {node: '>=10.0.0'}
peerDependencies:
postcss: ^8.0.0
@@ -7518,10 +7556,21 @@ packages:
postcss: 8.4.5
dev: false
+ /postcss-js/4.0.0_postcss@8.4.12:
+ resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==}
+ engines: {node: ^12 || ^14 || >= 16}
+ peerDependencies:
+ postcss: ^8.3.3
+ dependencies:
+ camelcase-css: 2.0.1
+ postcss: 8.4.12
+ dev: false
+
/postcss-load-config/3.1.0_ts-node@10.4.0:
resolution: {integrity: sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==}
engines: {node: '>= 10'}
peerDependencies:
+ postcss: '*'
ts-node: '>=9.0.0'
peerDependenciesMeta:
ts-node:
@@ -7533,16 +7582,36 @@ packages:
yaml: 1.10.2
dev: false
- /postcss-load-config/3.1.3_ts-node@10.4.0:
+ /postcss-load-config/3.1.3_postcss@8.4.12+ts-node@10.4.0:
resolution: {integrity: sha512-5EYgaM9auHGtO//ljHH+v/aC/TQ5LHXtL7bQajNAUBKUVKiYE8rYpFms7+V26D9FncaGe2zwCoPQsFKb5zF/Hw==}
engines: {node: '>= 10'}
peerDependencies:
+ postcss: '*'
ts-node: '>=9.0.0'
peerDependenciesMeta:
ts-node:
optional: true
dependencies:
lilconfig: 2.0.4
+ postcss: 8.4.12
+ ts-node: 10.4.0_44ef5af6cbbc24239b4e70b5c7b0d7a6
+ yaml: 1.10.2
+ dev: false
+
+ /postcss-load-config/3.1.4_postcss@8.4.12+ts-node@10.4.0:
+ resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
+ engines: {node: '>= 10'}
+ peerDependencies:
+ postcss: '>=8.0.9'
+ ts-node: '>=9.0.0'
+ peerDependenciesMeta:
+ postcss:
+ optional: true
+ ts-node:
+ optional: true
+ dependencies:
+ lilconfig: 2.0.5
+ postcss: 8.4.12
ts-node: 10.4.0_44ef5af6cbbc24239b4e70b5c7b0d7a6
yaml: 1.10.2
dev: true
@@ -7612,6 +7681,16 @@ packages:
dependencies:
postcss-selector-parser: 6.0.8
+ /postcss-nested/5.0.6_postcss@8.4.12:
+ resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==}
+ engines: {node: '>=12.0'}
+ peerDependencies:
+ postcss: ^8.2.14
+ dependencies:
+ postcss: 8.4.12
+ postcss-selector-parser: 6.0.8
+ dev: false
+
/postcss-selector-parser/6.0.8:
resolution: {integrity: sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==}
engines: {node: '>=4'}
@@ -7619,6 +7698,14 @@ packages:
cssesc: 3.0.0
util-deprecate: 1.0.2
+ /postcss-selector-parser/6.0.9:
+ resolution: {integrity: sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+ dev: false
+
/postcss-value-parser/3.3.1:
resolution: {integrity: sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==}
dev: false
@@ -7656,8 +7743,8 @@ packages:
engines: {node: '>= 0.8.0'}
dev: true
- /prettier/2.6.0:
- resolution: {integrity: sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==}
+ /prettier/2.6.2:
+ resolution: {integrity: sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==}
engines: {node: '>=10.13.0'}
hasBin: true
dev: true
@@ -7930,8 +8017,8 @@ packages:
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
dev: true
- /react-refresh/0.11.0:
- resolution: {integrity: sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==}
+ /react-refresh/0.12.0:
+ resolution: {integrity: sha512-suLIhrU2IHKL5JEKR/fAwJv7bbeq4kJ+pJopf77jHwuR+HmJS/HbrPIGsTBUVfw7tXPOmYv7UJ7PCaN49e8x4A==}
engines: {node: '>=0.10.0'}
dev: false
@@ -8053,7 +8140,7 @@ packages:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
dependencies:
- picomatch: 2.3.0
+ picomatch: 2.3.1
/redent/3.0.0:
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
@@ -8850,6 +8937,38 @@ packages:
- ts-node
dev: false
+ /tailwindcss/3.0.23_ts-node@10.4.0:
+ resolution: {integrity: sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA==}
+ engines: {node: '>=12.13.0'}
+ hasBin: true
+ peerDependencies:
+ autoprefixer: ^10.0.2
+ dependencies:
+ arg: 5.0.1
+ chalk: 4.1.2
+ chokidar: 3.5.3
+ color-name: 1.1.4
+ cosmiconfig: 7.0.1
+ detective: 5.2.0
+ didyoumean: 1.2.2
+ dlv: 1.1.3
+ fast-glob: 3.2.11
+ glob-parent: 6.0.2
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ object-hash: 2.2.0
+ postcss: 8.4.12
+ postcss-js: 4.0.0_postcss@8.4.12
+ postcss-load-config: 3.1.3_postcss@8.4.12+ts-node@10.4.0
+ postcss-nested: 5.0.6_postcss@8.4.12
+ postcss-selector-parser: 6.0.9
+ postcss-value-parser: 4.2.0
+ quick-lru: 5.1.1
+ resolve: 1.22.0
+ transitivePeerDependencies:
+ - ts-node
+ dev: false
+
/tar/6.1.11:
resolution: {integrity: sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==}
engines: {node: '>= 10'}
@@ -9014,15 +9133,15 @@ packages:
utf8-byte-length: 1.0.4
dev: true
- /ts-jest/27.1.3_4dfe14e0e8266437469ae0475a5c09ac:
- resolution: {integrity: sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==}
+ /ts-jest/27.1.4_4dfe14e0e8266437469ae0475a5c09ac:
+ resolution: {integrity: sha512-qjkZlVPWVctAezwsOD1OPzbZ+k7zA5z3oxII4dGdZo5ggX/PL7kvwTM0pXTr10fAtbiVpJaL3bWd502zAhpgSQ==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
hasBin: true
peerDependencies:
'@babel/core': '>=7.0.0-beta.0 <8'
'@types/jest': ^27.0.0
babel-jest: '>=27.0.0 <28'
- esbuild: ~0.14.0
+ esbuild: '*'
jest: ^27.0.0
typescript: '>=3.8 <5.0'
peerDependenciesMeta:
@@ -9040,8 +9159,8 @@ packages:
esbuild: 0.14.27
fast-json-stable-stringify: 2.1.0
jest: 27.5.1_ts-node@10.4.0
- jest-util: 27.4.2
- json5: 2.2.0
+ jest-util: 27.5.1
+ json5: 2.2.1
lodash.memoize: 4.1.2
make-error: 1.3.6
semver: 7.3.5
@@ -9079,8 +9198,8 @@ packages:
yn: 3.1.1
dev: true
- /tsconfck/1.2.0_typescript@4.5.4:
- resolution: {integrity: sha512-uKBM6x6i5e7Tfof5Zhll2ypgYKwWZhsxsHOoCH/7enlcHjjlcZ8FnxFrqgVFtpN6ymzZX3zoDaVGIlkh/g4x6w==}
+ /tsconfck/1.2.2_typescript@4.5.4:
+ resolution: {integrity: sha512-x5YpjOqjJnMs1EsJvQBQbrysrY32eGoZRRr5YvbN1hwlrXKc7jiphCOUrT7xbFdOWk8sh+EtMYbGPbTO8rDmcw==}
engines: {node: ^12.20 || ^14.13.1 || >= 16}
hasBin: true
peerDependencies:
diff --git a/scripts/jestGlobalSetup.cjs b/scripts/jestGlobalSetup.cjs
index 9640f70c5a8291..7341cba40968d9 100644
--- a/scripts/jestGlobalSetup.cjs
+++ b/scripts/jestGlobalSetup.cjs
@@ -21,11 +21,21 @@ module.exports = async () => {
const tempDir = path.resolve(__dirname, '../packages/temp')
await fs.remove(tempDir)
- await fs.copy(path.resolve(__dirname, '../packages/playground'), tempDir, {
- dereference: false,
- filter(file) {
- file = file.replace(/\\/g, '/')
- return !file.includes('__tests__') && !file.match(/dist(\/|$)/)
- }
- })
+ await fs
+ .copy(path.resolve(__dirname, '../packages/playground'), tempDir, {
+ dereference: false,
+ filter(file) {
+ file = file.replace(/\\/g, '/')
+ return !file.includes('__tests__') && !file.match(/dist(\/|$)/)
+ }
+ })
+ .catch(async (error) => {
+ if (error.code === 'EPERM' && error.syscall === 'symlink') {
+ throw new Error(
+ 'Could not create symlinks. On Windows, consider activating Developer Mode to allow non-admin users to create symlinks by following the instructions at https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development.'
+ )
+ } else {
+ throw error
+ }
+ })
}
diff --git a/scripts/jestGlobalTeardown.cjs b/scripts/jestGlobalTeardown.cjs
index 583aa1d1caf4ce..fc3370d626683a 100644
--- a/scripts/jestGlobalTeardown.cjs
+++ b/scripts/jestGlobalTeardown.cjs
@@ -4,6 +4,6 @@ const path = require('path')
module.exports = async () => {
await global.__BROWSER_SERVER__.close()
if (!process.env.VITE_PRESERVE_BUILD_ARTIFACTS) {
- await fs.remove(path.resolve(__dirname, '../packages/temp'))
+ fs.removeSync(path.resolve(__dirname, '../packages/temp'))
}
}
diff --git a/scripts/jestPerTestSetup.ts b/scripts/jestPerTestSetup.ts
index 530634f7b993d3..fcdca77ee9a6eb 100644
--- a/scripts/jestPerTestSetup.ts
+++ b/scripts/jestPerTestSetup.ts
@@ -4,12 +4,12 @@ import { resolve, dirname } from 'path'
import sirv from 'sirv'
import type {
ViteDevServer,
- UserConfig,
+ InlineConfig,
PluginOption,
ResolvedConfig,
Logger
} from 'vite'
-import { createServer, build } from 'vite'
+import { createServer, build, mergeConfig } from 'vite'
import type { Page, ConsoleMessage } from 'playwright-chromium'
import type { RollupError, RollupWatcher, RollupWatcherEvent } from 'rollup'
@@ -90,9 +90,16 @@ beforeAll(async () => {
}
}
+ const testCustomConfig = resolve(dirname(testPath), 'vite.config.js')
+ let config: InlineConfig | undefined
+ if (fs.existsSync(testCustomConfig)) {
+ // test has custom server configuration.
+ config = require(testCustomConfig)
+ }
+
const serverLogs: string[] = []
- const options: UserConfig = {
+ const options: InlineConfig = {
root: rootDir,
logLevel: 'silent',
server: {
@@ -120,7 +127,9 @@ beforeAll(async () => {
if (!isBuildTest) {
process.env.VITE_INLINE = 'inline-serve'
- server = await (await createServer(options)).listen()
+ server = await (
+ await createServer(mergeConfig(options, config || {}))
+ ).listen()
// use resolved port/base from server
const base = server.config.base === '/' ? '' : server.config.base
const url =
@@ -137,14 +146,14 @@ beforeAll(async () => {
}
})
options.plugins = [resolvedPlugin()]
- const rollupOutput = await build(options)
+ const rollupOutput = await build(mergeConfig(options, config || {}))
const isWatch = !!resolvedConfig!.build.watch
// in build watch,call startStaticServer after the build is complete
if (isWatch) {
global.watcher = rollupOutput as RollupWatcher
await notifyRebuildComplete(global.watcher)
}
- const url = (global.viteTestUrl = await startStaticServer(isWatch))
+ const url = (global.viteTestUrl = await startStaticServer(config))
await page.goto(url)
}
}
@@ -173,13 +182,15 @@ afterAll(async () => {
}
})
-function startStaticServer(isWatch: boolean): Promise {
- // check if the test project has base config
- const configFile = resolve(rootDir, 'vite.config.js')
- let config: UserConfig | undefined
- try {
- config = require(configFile)
- } catch (e) {}
+function startStaticServer(config?: InlineConfig): Promise {
+ if (!config) {
+ // check if the test project has base config
+ const configFile = resolve(rootDir, 'vite.config.js')
+ try {
+ config = require(configFile)
+ } catch (e) {}
+ }
+
// fallback internal base to ''
const base = (config?.base ?? '/') === '/' ? '' : config?.base ?? ''
@@ -190,7 +201,7 @@ function startStaticServer(isWatch: boolean): Promise {
}
// start static file server
- const serve = sirv(resolve(rootDir, 'dist'), { dev: isWatch })
+ const serve = sirv(resolve(rootDir, 'dist'), { dev: !!config?.build?.watch })
const httpServer = (server = http.createServer((req, res) => {
if (req.url === '/ping') {
res.statusCode = 200
diff --git a/scripts/release.ts b/scripts/release.ts
index d536eca1f70586..5c32c13b5cf5c8 100644
--- a/scripts/release.ts
+++ b/scripts/release.ts
@@ -88,7 +88,7 @@ async function main(): Promise {
'--commit-path',
'.'
]
- if (pkgName !== 'vite') changelogArgs.push('--lerna-package', 'plugin-vue')
+ if (pkgName !== 'vite') changelogArgs.push('--lerna-package', pkgName)
await run('npx', changelogArgs, { cwd: pkgDir })
const { stdout } = await run('git', ['diff'], { stdio: 'pipe' })