diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dfccbea368c449..cde7dfb03825ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,8 @@ on: - main - release/* - feat/* + - fix/* + - perf/* pull_request: workflow_dispatch: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a87561a8e4146c..f086627de5cfe0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ If you want to use break point and explore code execution you can use the ["Run 2. Click on the "Run and Debug" icon in the activity bar of the editor. -3. Click on the "Javascript Debug Terminal" button. +3. Click on the "JavaScript Debug Terminal" button. 4. It will open a terminal, then go to `packages/playground/xxx` and run `pnpm run dev`. @@ -79,7 +79,7 @@ Each test can be run under either dev server mode or build mode. - `pnpm run test-build` runs tests only under build mode. -- You can also use `pnpm run test-serve -- [match]` or `pnpm run test-build -- [match]` to run tests in a specific playground package, e.g. `pnpm run test-serve -- css` will run tests for both `playground/css` and `playground/css-codesplit` under serve mode. +- You can also use `pnpm run test-serve -- [match]` or `pnpm run test-build -- [match]` to run tests in a specific playground package, e.g. `pnpm run test-serve -- asset` will run tests for both `playground/asset` and `vite/src/node/__tests__/asset` under serve mode and `vite/src/node/__tests__/**/*` just run in serve mode. Note package matching is not available for the `pnpm test` script, which always runs all tests. @@ -229,7 +229,7 @@ The english docs are embedded in the main Vite repo, to allow contributors to wo 1. In order to get all doc files, you first need to clone this repo in your personal account. 2. Keep all the files in `docs/` and remove everything else. - - You should setup your translation site based on all the files in `docs/` folder as a Vitepress project. + - You should setup your translation site based on all the files in `docs/` folder as a VitePress project. (that said, `package.json` is need). - Refresh git history by removing `.git` and then `git init` @@ -238,7 +238,7 @@ The english docs are embedded in the main Vite repo, to allow contributors to wo - During this stage, you may be translating documents and synchronizing updates at the same time, but don't worry about that, it's very common in translation contribution. -4. Push your commits to your Github repo. you can setup a netlify preview as well. -5. Use [Ryu-cho](https://github.com/vuejs-translations/ryu-cho) tool to setup a Github Action, automatically track English docs update later. +4. Push your commits to your GitHub repo. you can setup a netlify preview as well. +5. Use [Ryu-cho](https://github.com/vuejs-translations/ryu-cho) tool to setup a GitHub Action, automatically track English docs update later. We recommend talking with others in Vite Land so you find more contributors for your language to share the maintenance work. Once the translation is done, communicate it to the Vite team so the repo can be moved to the official vitejs org in GitHub. diff --git a/docs/blog/announcing-vite2.md b/docs/blog/announcing-vite2.md index 0bf520dfdfcb9a..0007205debba4a 100644 --- a/docs/blog/announcing-vite2.md +++ b/docs/blog/announcing-vite2.md @@ -34,7 +34,7 @@ The [programmatic API](https://vitejs.dev/guide/api-javascript.html) has also be ### esbuild Powered Dep Pre-Bundling -Since Vite is a native ESM dev server, it pre-bundles dependencies to reduce the number browser requests and handle CommonJS to ESM conversion. Previously Vite did this using Rollup, and in 2.0 it now uses `esbuild` which results in 10-100x faster dependency pre-bundling. As a reference, cold-booting a test app with heavy dependencies like React Material UI previously took 28 seconds on an M1-powered Macbook Pro and now takes ~1.5 seconds. Expect similar improvements if you are switching from a traditional bundler based setup. +Since Vite is a native ESM dev server, it pre-bundles dependencies to reduce the number browser requests and handle CommonJS to ESM conversion. Previously Vite did this using Rollup, and in 2.0 it now uses `esbuild` which results in 10-100x faster dependency pre-bundling. As a reference, cold-booting a test app with heavy dependencies like React Material UI previously took 28 seconds on an M1-powered MacBook Pro and now takes ~1.5 seconds. Expect similar improvements if you are switching from a traditional bundler based setup. ### First-class CSS Support diff --git a/docs/config/index.md b/docs/config/index.md index b0d2f59d4a62af..d7560e58736a43 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -156,6 +156,8 @@ export default defineConfig(({ command, mode }) => { - Starting from `2.0.0-beta.70`, string values will be used as raw expressions, so if defining a string constant, it needs to be explicitly quoted (e.g. with `JSON.stringify`). + - To be consistent with [esbuild behavior](https://esbuild.github.io/api/#define), expressions must either be a JSON object (null, boolean, number, string, array, or object) or a single identifier. + - Replacements are performed only when the match is surrounded by word boundaries (`\b`). ::: warning @@ -355,7 +357,7 @@ export default defineConfig(({ command, mode }) => { - **Type:** `ESBuildOptions | false` - `ESBuildOptions` extends [ESbuild's own transform options](https://esbuild.github.io/api/#transform-api). The most common use case is customizing JSX: + `ESBuildOptions` extends [esbuild's own transform options](https://esbuild.github.io/api/#transform-api). The most common use case is customizing JSX: ```js export default defineConfig({ @@ -366,9 +368,9 @@ export default defineConfig(({ command, mode }) => { }) ``` - By default, ESBuild is applied to `ts`, `jsx` and `tsx` files. You can customize this with `esbuild.include` and `esbuild.exclude`, which can be a regex, a [picomatch](https://github.com/micromatch/picomatch#globbing-features) pattern, or an array of either. + By default, esbuild is applied to `ts`, `jsx` and `tsx` files. You can customize this with `esbuild.include` and `esbuild.exclude`, which can be a regex, a [picomatch](https://github.com/micromatch/picomatch#globbing-features) pattern, or an array of either. - In addition, you can also use `esbuild.jsxInject` to automatically inject JSX helper imports for every file transformed by ESBuild: + In addition, you can also use `esbuild.jsxInject` to automatically inject JSX helper imports for every file transformed by esbuild: ```js export default defineConfig({ @@ -378,7 +380,7 @@ export default defineConfig(({ command, mode }) => { }) ``` - Set to `false` to disable ESbuild transforms. + Set to `false` to disable esbuild transforms. ### assetsInclude @@ -550,14 +552,12 @@ export default defineConfig(({ command, mode }) => { ### server.hmr -- **Type:** `boolean | { protocol?: string, host?: string, port?: number | false, path?: string, timeout?: number, overlay?: boolean, clientPort?: number, server?: Server }` +- **Type:** `boolean | { protocol?: string, host?: string, port?: number, path?: string, timeout?: number, overlay?: boolean, clientPort?: number, server?: Server }` Disable or configure HMR connection (in cases where the HMR websocket must use a different address from the http server). Set `server.hmr.overlay` to `false` to disable the server error overlay. - Set `server.hmr.port` to `false` when connecting to a domain without a port. - `clientPort` is an advanced option that overrides the port only on the client side, allowing you to serve the websocket on a different port than the client code looks for it on. Useful if you're using an SSL proxy in front of your dev server. If specifying `server.hmr.server`, Vite will process HMR connection requests through the provided server. If not in middleware mode, Vite will attempt to process HMR connection requests through the existing server. This can be helpful when using self-signed certificates or when you want to expose Vite over a network on a single port. @@ -849,7 +849,7 @@ export default defineConfig({ - **Type:** `boolean | 'terser' | 'esbuild'` - **Default:** `'esbuild'` - Set to `false` to disable minification, or specify the minifier to use. The default is [Esbuild](https://github.com/evanw/esbuild) which is 20 ~ 40x faster than terser and only 1 ~ 2% worse compression. [Benchmarks](https://github.com/privatenumber/minification-benchmarks) + Set to `false` to disable minification, or specify the minifier to use. The default is [esbuild](https://github.com/evanw/esbuild) which is 20 ~ 40x faster than terser and only 1 ~ 2% worse compression. [Benchmarks](https://github.com/privatenumber/minification-benchmarks) Note the `build.minify` option is not available when using the `'es'` format in lib mode. @@ -973,9 +973,9 @@ export default defineConfig({ - **Type:** `string | string[]` - By default, Vite will crawl your `index.html` to detect dependencies that need to be pre-bundled. If `build.rollupOptions.input` is specified, Vite will crawl those entry points instead. + By default, Vite will crawl all your `.html` files to detect dependencies that need to be pre-bundled (ignoring `node_modules`, `build.outDir`, `__tests__` and `coverage`). If `build.rollupOptions.input` is specified, Vite will crawl those entry points instead. - If neither of these fit your needs, you can specify custom entries using this option - the value should be a [fast-glob pattern](https://github.com/mrmlnc/fast-glob#basic-syntax) or array of patterns that are relative from Vite project root. This will overwrite default entries inference. + If neither of these fit your needs, you can specify custom entries using this option - the value should be a [fast-glob pattern](https://github.com/mrmlnc/fast-glob#basic-syntax) or array of patterns that are relative from Vite project root. This will overwrite default entries inference. Only `node_modules` and `build.outDir` folders will be ignored by default when `optimizeDeps.entries` is explicitily defined. If other folders needs to be ignored, you can use an ignore pattern as part of the entries list, marked with an initial `!`. ### optimizeDeps.exclude diff --git a/docs/guide/api-javascript.md b/docs/guide/api-javascript.md index ddaa04279737f5..0128be26bd92ba 100644 --- a/docs/guide/api-javascript.md +++ b/docs/guide/api-javascript.md @@ -1,6 +1,6 @@ # JavaScript API -Vite's JavaScript APIs are fully typed, and it's recommended to use TypeScript or enable JS type checking in VSCode to leverage the intellisense and validation. +Vite's JavaScript APIs are fully typed, and it's recommended to use TypeScript or enable JS type checking in VS Code to leverage the intellisense and validation. ## `createServer` diff --git a/docs/guide/api-plugin.md b/docs/guide/api-plugin.md index 228755dd6f85c2..50353765261e34 100644 --- a/docs/guide/api-plugin.md +++ b/docs/guide/api-plugin.md @@ -113,7 +113,7 @@ Virtual modules are a useful scheme that allows you to pass build time informati ```js export default function myPlugin() { - const virtualModuleId = '@my-virtual-module' + const virtualModuleId = 'virtual:my-module' const resolvedVirtualModuleId = '\0' + virtualModuleId return { @@ -135,7 +135,7 @@ export default function myPlugin() { Which allows importing the module in JavaScript: ```js -import { msg } from '@my-virtual-module' +import { msg } from 'virtual:my-module' console.log(msg) ``` @@ -186,8 +186,10 @@ Vite plugins can also provide hooks that serve Vite-specific purposes. These hoo const partialConfigPlugin = () => ({ name: 'return-partial', config: () => ({ - alias: { - foo: 'bar' + resolve: { + alias: { + foo: 'bar' + } } }) }) @@ -499,7 +501,7 @@ Since Vite 2.9, we provide some utilities for plugins to help handle the communi ### Server to Client -On the plugin side, we could use `server.ws.send` to boardcast events to all the clients: +On the plugin side, we could use `server.ws.send` to broadcast events to all the clients: ```js // vite.config.js diff --git a/docs/guide/assets.md b/docs/guide/assets.md index fd5aa46f49467f..9776dcdd032f35 100644 --- a/docs/guide/assets.md +++ b/docs/guide/assets.md @@ -103,8 +103,17 @@ function getImageUrl(name) { } ``` -During the production build, Vite will perform necessary transforms so that the URLs still point to the correct location even after bundling and asset hashing. +During the production build, Vite will perform necessary transforms so that the URLs still point to the correct location even after bundling and asset hashing. However, the URL string must be static so it can be analyzed, otherwise the code will be left as is, which can cause runtime errors if `build.target` does not support `import.meta.url` -::: warning Note: Does not work with SSR +```js +// Vite will not transform this +const imgUrl = new URL(imagePath, import.meta.url).href +``` + +::: warning Does not work with SSR This pattern does not work if you are using Vite for Server-Side Rendering, because `import.meta.url` have different semantics in browsers vs. Node.js. The server bundle also cannot determine the client host URL ahead of time. ::: + +::: warning Esbuild target config is necessary +This pattern needs esbuild target to be set to `es2020` or higher. `vite@2.x` use `es2019` as default target. Set [build-target](https://vitejs.dev/config/#build-target) and [optimizedeps.esbuildoptions.target](https://vitejs.dev/config/#optimizedeps-esbuildoptions) to `es2020` or higher if you intend to use this partten. +::: diff --git a/docs/guide/env-and-mode.md b/docs/guide/env-and-mode.md index d3a6a575bce64c..1649feda8c7501 100644 --- a/docs/guide/env-and-mode.md +++ b/docs/guide/env-and-mode.md @@ -37,7 +37,7 @@ Vite uses [dotenv](https://github.com/motdotla/dotenv) to load additional enviro An env file for a specific mode (e.g. `.env.production`) will take higher priority than a generic one (e.g. `.env`). -In addition, environment variables that already exist when Vite is executed have the highest priority and will not be overwritten by `.env` files. +In addition, environment variables that already exist when Vite is executed have the highest priority and will not be overwritten by `.env` files. For example, when running `VITE_SOME_KEY=123 vite build`. `.env` files are loaded at the start of Vite. Restart the server after making changes. ::: @@ -57,7 +57,7 @@ If you want to customize env variables prefix, see [envPrefix](/config/index#env :::warning SECURITY NOTES -- `.env.*.local` files are local-only and can contain sensitive variables. You should add `.local` to your `.gitignore` to avoid them being checked into git. +- `.env.*.local` files are local-only and can contain sensitive variables. You should add `*.local` to your `.gitignore` to avoid them being checked into git. - Since any variables exposed to your Vite source code will end up in your client bundle, `VITE_*` variables should _not_ contain any sensitive information. ::: diff --git a/docs/guide/static-deploy.md b/docs/guide/static-deploy.md index 43b047dd7f53eb..8c6c219f568a9e 100644 --- a/docs/guide/static-deploy.md +++ b/docs/guide/static-deploy.md @@ -299,7 +299,7 @@ Vercel CLI ### Vercel for Git -1. Push your code to your git repository (GitHub, GitLab, BitBucket). +1. Push your code to your git repository (GitHub, GitLab, Bitbucket). 2. [Import your Vite project](https://vercel.com/new) into Vercel. 3. Vercel will detect that you are using Vite and will enable the correct settings for your deployment. 4. Your application is deployed! (e.g. [vite-vue-template.vercel.app](https://vite-vue-template.vercel.app/)) diff --git a/docs/guide/why.md b/docs/guide/why.md index 89ca7698394246..9a24cf64777611 100644 --- a/docs/guide/why.md +++ b/docs/guide/why.md @@ -18,7 +18,7 @@ Vite improves the dev server start time by first dividing the modules in an appl - **Dependencies** are mostly plain JavaScript that do not change often during development. Some large dependencies (e.g. component libraries with hundreds of modules) are also quite expensive to process. Dependencies may also be shipped in various module formats (e.g. ESM or CommonJS). - Vite [pre-bundles dependencies](./dep-pre-bundling) using [esbuild](https://esbuild.github.io/). Esbuild is written in Go and pre-bundles dependencies 10-100x faster than JavaScript-based bundlers. + Vite [pre-bundles dependencies](./dep-pre-bundling) using [esbuild](https://esbuild.github.io/). esbuild is written in Go and pre-bundles dependencies 10-100x faster than JavaScript-based bundlers. - **Source code** often contains non-plain JavaScript that needs transforming (e.g. JSX, CSS or Vue/Svelte components), and will be edited very often. Also, not all source code needs to be loaded at the same time (e.g. with route-based code-splitting). diff --git a/package.json b/package.json index 858e7502d53324..de02e27949560c 100644 --- a/package.json +++ b/package.json @@ -34,37 +34,37 @@ "ci-docs": "run-s build-vite build-plugin-vue build-docs" }, "devDependencies": { - "@microsoft/api-extractor": "^7.19.5", + "@microsoft/api-extractor": "^7.21.2", "@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.18.0", + "@typescript-eslint/parser": "^5.18.0", "conventional-changelog-cli": "^2.2.2", "cross-env": "^7.0.3", "esbuild": "^0.14.27", - "eslint": "^8.11.0", + "eslint": "^8.13.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", + "semver": "^7.3.6", "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:*", @@ -85,11 +85,18 @@ "eslint --ext .ts" ] }, - "packageManager": "pnpm@6.32.3", + "packageManager": "pnpm@6.32.6", "pnpm": { "overrides": { "vite": "workspace:*", "@vitejs/plugin-vue": "workspace:*" + }, + "packageExtensions": { + "postcss-load-config": { + "peerDependencies": { + "postcss": "*" + } + } } } } diff --git a/packages/create-vite/CHANGELOG.md b/packages/create-vite/CHANGELOG.md index b81d7ec6fac49a..bf69fae7e535ad 100644 --- a/packages/create-vite/CHANGELOG.md +++ b/packages/create-vite/CHANGELOG.md @@ -1,3 +1,12 @@ +## 2.9.0 (2022-03-30) + +* chore: add isolatedModules to create-vite > template-vue-ts > tsconfig (#7304) ([21990ea](https://github.com/vitejs/vite/commit/21990ea)), closes [#7304](https://github.com/vitejs/vite/issues/7304) +* chore(deps): update all non-major dependencies (#7490) ([42c15f6](https://github.com/vitejs/vite/commit/42c15f6)), closes [#7490](https://github.com/vitejs/vite/issues/7490) +* docs(vue-ts): update note on vue type support in ts (#6165) ([cfc7648](https://github.com/vitejs/vite/commit/cfc7648)), closes [#6165](https://github.com/vitejs/vite/issues/6165) +* 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) + + + # [2.8.0](https://github.com/vitejs/vite/compare/create-vite@2.7.2...create-vite@2.8.0) (2022-02-09) diff --git a/packages/create-vite/package.json b/packages/create-vite/package.json index 5d873b83fe515b..72955697360477 100644 --- a/packages/create-vite/package.json +++ b/packages/create-vite/package.json @@ -1,6 +1,6 @@ { "name": "create-vite", - "version": "2.8.0", + "version": "2.9.0", "license": "MIT", "author": "Evan You", "bin": { @@ -26,7 +26,7 @@ "homepage": "https://github.com/vitejs/vite/tree/main/packages/create-vite#readme", "dependencies": { "kolorist": "^1.5.1", - "minimist": "^1.2.5", + "minimist": "^1.2.6", "prompts": "^2.4.2" } } diff --git a/packages/create-vite/template-lit-ts/package.json b/packages/create-vite/template-lit-ts/package.json index 5c0a7c7948ee58..061def321a22e6 100644 --- a/packages/create-vite/template-lit-ts/package.json +++ b/packages/create-vite/template-lit-ts/package.json @@ -19,7 +19,7 @@ "lit": "^2.0.2" }, "devDependencies": { - "vite": "^2.8.0", + "vite": "^2.9.0", "typescript": "^4.5.4" } } diff --git a/packages/create-vite/template-lit/package.json b/packages/create-vite/template-lit/package.json index ca3c71428f22c9..89f4fee41576c6 100644 --- a/packages/create-vite/template-lit/package.json +++ b/packages/create-vite/template-lit/package.json @@ -17,6 +17,6 @@ "lit": "^2.0.2" }, "devDependencies": { - "vite": "^2.8.0" + "vite": "^2.9.0" } } diff --git a/packages/create-vite/template-preact-ts/package.json b/packages/create-vite/template-preact-ts/package.json index df1726ba6c4f7b..dfa6659650c5ae 100644 --- a/packages/create-vite/template-preact-ts/package.json +++ b/packages/create-vite/template-preact-ts/package.json @@ -13,6 +13,6 @@ "devDependencies": { "@preact/preset-vite": "^2.1.5", "typescript": "^4.5.4", - "vite": "^2.8.0" + "vite": "^2.9.0" } } diff --git a/packages/create-vite/template-preact/package.json b/packages/create-vite/template-preact/package.json index 2865df70374acf..02528128f6442e 100644 --- a/packages/create-vite/template-preact/package.json +++ b/packages/create-vite/template-preact/package.json @@ -12,6 +12,6 @@ }, "devDependencies": { "@preact/preset-vite": "^2.1.5", - "vite": "^2.8.0" + "vite": "^2.9.0" } } diff --git a/packages/create-vite/template-react-ts/package.json b/packages/create-vite/template-react-ts/package.json index 3b1e21b7dbca8c..69274929dd903d 100644 --- a/packages/create-vite/template-react-ts/package.json +++ b/packages/create-vite/template-react-ts/package.json @@ -8,14 +8,14 @@ "preview": "vite preview" }, "dependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.0.0", + "react-dom": "^18.0.0" }, "devDependencies": { - "@types/react": "^17.0.33", - "@types/react-dom": "^17.0.10", - "@vitejs/plugin-react": "^1.0.7", - "typescript": "^4.5.4", - "vite": "^2.8.0" + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@vitejs/plugin-react": "^1.3.0", + "typescript": "^4.6.3", + "vite": "^2.9.1" } } diff --git a/packages/create-vite/template-react-ts/src/main.tsx b/packages/create-vite/template-react-ts/src/main.tsx index 606a3cf44ec02b..4a1b15096e15b1 100644 --- a/packages/create-vite/template-react-ts/src/main.tsx +++ b/packages/create-vite/template-react-ts/src/main.tsx @@ -1,11 +1,10 @@ import React from 'react' -import ReactDOM from 'react-dom' -import './index.css' +import ReactDOM from 'react-dom/client' import App from './App' +import './index.css' -ReactDOM.render( +ReactDOM.createRoot(document.getElementById('root')!).render( - , - document.getElementById('root') + ) diff --git a/packages/create-vite/template-react/package.json b/packages/create-vite/template-react/package.json index 7b0f87c6bc95f5..4f443aefcb3cdb 100644 --- a/packages/create-vite/template-react/package.json +++ b/packages/create-vite/template-react/package.json @@ -8,11 +8,13 @@ "preview": "vite preview" }, "dependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.0.0", + "react-dom": "^18.0.0" }, "devDependencies": { - "@vitejs/plugin-react": "^1.0.7", - "vite": "^2.8.0" + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@vitejs/plugin-react": "^1.3.0", + "vite": "^2.9.1" } } diff --git a/packages/create-vite/template-react/src/main.jsx b/packages/create-vite/template-react/src/main.jsx index 606a3cf44ec02b..9af0bb638e42c0 100644 --- a/packages/create-vite/template-react/src/main.jsx +++ b/packages/create-vite/template-react/src/main.jsx @@ -1,11 +1,10 @@ import React from 'react' -import ReactDOM from 'react-dom' -import './index.css' +import ReactDOM from 'react-dom/client' import App from './App' +import './index.css' -ReactDOM.render( +ReactDOM.createRoot(document.getElementById('root')).render( - , - document.getElementById('root') + ) diff --git a/packages/create-vite/template-svelte-ts/README.md b/packages/create-vite/template-svelte-ts/README.md index a9d516a32c682e..4ef762ffec4df3 100644 --- a/packages/create-vite/template-svelte-ts/README.md +++ b/packages/create-vite/template-svelte-ts/README.md @@ -4,7 +4,7 @@ This template should help get you started developing with Svelte and TypeScript ## Recommended IDE Setup -[VSCode](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). +[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). ## Need an official Svelte framework? diff --git a/packages/create-vite/template-svelte-ts/package.json b/packages/create-vite/template-svelte-ts/package.json index 3f2c63759285e5..32e080146e0b6e 100644 --- a/packages/create-vite/template-svelte-ts/package.json +++ b/packages/create-vite/template-svelte-ts/package.json @@ -17,6 +17,6 @@ "svelte-preprocess": "^4.9.8", "tslib": "^2.3.1", "typescript": "^4.5.4", - "vite": "^2.8.0" + "vite": "^2.9.0" } } diff --git a/packages/create-vite/template-svelte/README.md b/packages/create-vite/template-svelte/README.md index 8e35d33d2bc7c8..50ea7ed3b9132d 100644 --- a/packages/create-vite/template-svelte/README.md +++ b/packages/create-vite/template-svelte/README.md @@ -4,7 +4,7 @@ This template should help get you started developing with Svelte in Vite. ## Recommended IDE Setup -[VSCode](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). +[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). ## Need an official Svelte framework? diff --git a/packages/create-vite/template-svelte/package.json b/packages/create-vite/template-svelte/package.json index e81ffa8288b6ef..da049c170731b9 100644 --- a/packages/create-vite/template-svelte/package.json +++ b/packages/create-vite/template-svelte/package.json @@ -11,6 +11,6 @@ "devDependencies": { "@sveltejs/vite-plugin-svelte": "^1.0.0-next.30", "svelte": "^3.44.0", - "vite": "^2.8.0" + "vite": "^2.9.0" } } diff --git a/packages/create-vite/template-vanilla-ts/package.json b/packages/create-vite/template-vanilla-ts/package.json index 9b6cc582bfdb11..8dd7a0bb800909 100644 --- a/packages/create-vite/template-vanilla-ts/package.json +++ b/packages/create-vite/template-vanilla-ts/package.json @@ -9,6 +9,6 @@ }, "devDependencies": { "typescript": "^4.5.4", - "vite": "^2.8.0" + "vite": "^2.9.0" } } diff --git a/packages/create-vite/template-vanilla/package.json b/packages/create-vite/template-vanilla/package.json index f409412bbdc272..ff318e00f14fd1 100644 --- a/packages/create-vite/template-vanilla/package.json +++ b/packages/create-vite/template-vanilla/package.json @@ -8,6 +8,6 @@ "preview": "vite preview" }, "devDependencies": { - "vite": "^2.8.0" + "vite": "^2.9.0" } } diff --git a/packages/create-vite/template-vue-ts/README.md b/packages/create-vite/template-vue-ts/README.md index b53dcfb1a715e6..e432516724c1a7 100644 --- a/packages/create-vite/template-vue-ts/README.md +++ b/packages/create-vite/template-vue-ts/README.md @@ -1,16 +1,16 @@ -# Vue 3 + Typescript + Vite +# Vue 3 + TypeScript + Vite -This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 ` diff --git a/packages/create-vite/template-vue-ts/src/components/HelloWorld.vue b/packages/create-vite/template-vue-ts/src/components/HelloWorld.vue index 2d61249ac32f9c..38dae70739a15a 100644 --- a/packages/create-vite/template-vue-ts/src/components/HelloWorld.vue +++ b/packages/create-vite/template-vue-ts/src/components/HelloWorld.vue @@ -11,7 +11,7 @@ const count = ref(0)

Recommended IDE setup: - VSCode + VS Code + Volar

diff --git a/packages/create-vite/template-vue/README.md b/packages/create-vite/template-vue/README.md index c0793a82398e08..eea15cef41ea60 100644 --- a/packages/create-vite/template-vue/README.md +++ b/packages/create-vite/template-vue/README.md @@ -4,4 +4,4 @@ This template should help get you started developing with Vue 3 in Vite. The tem ## Recommended IDE Setup -- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) +- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) diff --git a/packages/create-vite/template-vue/package.json b/packages/create-vite/template-vue/package.json index 3136fcda2a0bc7..707b664d3dfff7 100644 --- a/packages/create-vite/template-vue/package.json +++ b/packages/create-vite/template-vue/package.json @@ -11,7 +11,7 @@ "vue": "^3.2.25" }, "devDependencies": { - "@vitejs/plugin-vue": "^2.2.0", - "vite": "^2.8.0" + "@vitejs/plugin-vue": "^2.3.0", + "vite": "^2.9.0" } } diff --git a/packages/create-vite/template-vue/src/App.vue b/packages/create-vite/template-vue/src/App.vue index 742233037df99e..09bbb6a561285f 100644 --- a/packages/create-vite/template-vue/src/App.vue +++ b/packages/create-vite/template-vue/src/App.vue @@ -1,6 +1,6 @@ diff --git a/packages/create-vite/template-vue/src/components/HelloWorld.vue b/packages/create-vite/template-vue/src/components/HelloWorld.vue index 48a5ca9095156b..aa607e31e0ad7c 100644 --- a/packages/create-vite/template-vue/src/components/HelloWorld.vue +++ b/packages/create-vite/template-vue/src/components/HelloWorld.vue @@ -13,7 +13,7 @@ const count = ref(0)

Recommended IDE setup: - VSCode + VS Code + Volar

diff --git a/packages/playground/assets/__tests__/assets.spec.ts b/packages/playground/assets/__tests__/assets.spec.ts index f53c783c52b606..e08de24265e24a 100644 --- a/packages/playground/assets/__tests__/assets.spec.ts +++ b/packages/playground/assets/__tests__/assets.spec.ts @@ -263,6 +263,7 @@ if (isBuild) { } }) } + describe('css and assets in css in build watch', () => { if (isBuild) { test('css will not be lost and css does not contain undefined', async () => { @@ -271,7 +272,26 @@ describe('css and assets in css in build watch', () => { const cssFile = findAssetFile(/index\.\w+\.css$/, 'foo') expect(cssFile).not.toBe('') expect(cssFile).not.toMatch(/undefined/) - watcher?.close() + }) + + test('import module.css', async () => { + expect(await getColor('#foo')).toBe('red') + editFile( + 'css/foo.module.css', + (code) => code.replace('red', 'blue'), + true + ) + await notifyRebuildComplete(watcher) + await page.reload() + expect(await getColor('#foo')).toBe('blue') + }) + + test('import with raw query', async () => { + expect(await page.textContent('.raw-query')).toBe('foo') + editFile('static/foo.txt', (code) => code.replace('foo', 'zoo'), true) + await notifyRebuildComplete(watcher) + await page.reload() + expect(await page.textContent('.raw-query')).toBe('zoo') }) } }) diff --git a/packages/playground/assets/css/foo.module.css b/packages/playground/assets/css/foo.module.css new file mode 100644 index 00000000000000..196612f252d254 --- /dev/null +++ b/packages/playground/assets/css/foo.module.css @@ -0,0 +1,3 @@ +.foo-module { + color: red; +} diff --git a/packages/playground/assets/index.html b/packages/playground/assets/index.html index 1bf430e73de1df..472e51f4d404ee 100644 --- a/packages/playground/assets/index.html +++ b/packages/playground/assets/index.html @@ -227,6 +227,10 @@

@import

@import CSS from publicDir should load (this should be red)

+

import module css

+ +

+ @@ -283,6 +287,12 @@

document.querySelector('.import-meta-url-img-comma-nl').src = metaUrlWithCommaNL + import classNames from './css/foo.module.css' + document.querySelector('#foo').className = classNames['foo-module'] + + import someString from './static/foo.txt?raw' + document.querySelector('.raw-query').textContent = someString + const metaUrlNonExistent = new URL('non-existent', import.meta.url).pathname text('.non-existent-import-meta-url', metaUrlNonExistent) diff --git a/packages/playground/assets/static/foo.txt b/packages/playground/assets/static/foo.txt new file mode 100644 index 00000000000000..19102815663d23 --- /dev/null +++ b/packages/playground/assets/static/foo.txt @@ -0,0 +1 @@ +foo \ No newline at end of file diff --git a/packages/playground/cli-module/__tests__/serve.js b/packages/playground/cli-module/__tests__/serve.js index 2b354f566524bf..cf873fd481830b 100644 --- a/packages/playground/cli-module/__tests__/serve.js +++ b/packages/playground/cli-module/__tests__/serve.js @@ -5,10 +5,10 @@ const path = require('path') // eslint-disable-next-line node/no-restricted-require const execa = require('execa') -const { workspaceRoot } = require('../../testUtils') +const { workspaceRoot, ports } = require('../../testUtils') const isWindows = process.platform === 'win32' -const port = (exports.port = 9511) // make sure this port is unique across tests with custom servers +const port = (exports.port = ports['cli-module']) const viteBin = path.join(workspaceRoot, 'packages', 'vite', 'bin', 'vite.js') /** diff --git a/packages/playground/cli/__tests__/serve.js b/packages/playground/cli/__tests__/serve.js index 5dd058f4e1a83c..3ad375d9d1f543 100644 --- a/packages/playground/cli/__tests__/serve.js +++ b/packages/playground/cli/__tests__/serve.js @@ -5,10 +5,10 @@ const path = require('path') // eslint-disable-next-line node/no-restricted-require const execa = require('execa') -const { workspaceRoot } = require('../../testUtils') +const { workspaceRoot, ports } = require('../../testUtils') const isWindows = process.platform === 'win32' -const port = (exports.port = 9510) // make sure this port is unique across tests with custom servers +const port = (exports.port = ports.cli) const viteBin = path.join(workspaceRoot, 'packages', 'vite', 'bin', 'vite.js') /** diff --git a/packages/playground/css-sourcemap/__tests__/serve.spec.ts b/packages/playground/css-sourcemap/__tests__/serve.spec.ts index 0c6696b0dff7a2..11e33a78af8424 100644 --- a/packages/playground/css-sourcemap/__tests__/serve.spec.ts +++ b/packages/playground/css-sourcemap/__tests__/serve.spec.ts @@ -1,11 +1,11 @@ -import { fromComment } from 'convert-source-map' import { URL } from 'url' -import { normalizePath } from 'vite' -import { isBuild, testDir } from 'testUtils' +import { + extractSourcemap, + formatSourcemapForSnapshot, + isBuild +} from 'testUtils' if (!isBuild) { - const root = normalizePath(testDir) - const getStyleTagContentIncluding = async (content: string) => { const styles = await page.$$('style') for (const style of styles) { @@ -17,19 +17,6 @@ if (!isBuild) { throw new Error('Not found') } - const extractSourcemap = (content: string) => { - const lines = content.trim().split('\n') - return fromComment(lines[lines.length - 1]).toObject() - } - - 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 - } - test('inline css', async () => { const css = await getStyleTagContentIncluding('.inline ') const map = extractSourcemap(css) diff --git a/packages/playground/css-sourcemap/package.json b/packages/playground/css-sourcemap/package.json index c29f18d4dee0d7..c7e9e61372cefa 100644 --- a/packages/playground/css-sourcemap/package.json +++ b/packages/playground/css-sourcemap/package.json @@ -9,7 +9,6 @@ "preview": "vite preview" }, "devDependencies": { - "convert-source-map": "^1.8.0", "less": "^4.1.2", "magic-string": "^0.25.7", "sass": "^1.43.4", diff --git a/packages/playground/css/__tests__/css.spec.ts b/packages/playground/css/__tests__/css.spec.ts index 34858ab34bc09d..6ca00e760349b1 100644 --- a/packages/playground/css/__tests__/css.spec.ts +++ b/packages/playground/css/__tests__/css.spec.ts @@ -54,6 +54,12 @@ test('css import from js', async () => { await untilUpdated(() => getColor(atImport), 'blue') }) +test('css import asset with space', async () => { + const importedWithSpace = await page.$('.import-with-space') + + expect(await getBg(importedWithSpace)).toMatch(/.*ok\..*png/) +}) + test('postcss config', async () => { const imported = await page.$('.postcss .nesting') expect(await getColor(imported)).toBe('pink') @@ -236,6 +242,20 @@ test('css modules w/ sass', async () => { await untilUpdated(() => getColor(imported), 'blue') }) +test('inline css modules', async () => { + const css = await page.textContent('.modules-inline') + expect(css).toMatch(/\.inline-module__apply-color-inline___[\w-]{5}/) +}) + +if (isBuild) { + test('@charset hoist', async () => { + serverLogs.forEach((log) => { + // no warning from esbuild css minifier + expect(log).not.toMatch('"@charset" must be the first rule in the file') + }) + }) +} + test('@import dependency w/ style entry', async () => { expect(await getColor('.css-dep')).toBe('purple') }) @@ -318,7 +338,7 @@ test('PostCSS dir-dependency', async () => { } }) -test('Url separation', async () => { +test('URL separation', async () => { const urlSeparated = await page.$('.url-separated') const baseUrl = 'url(images/dog.webp)' const cases = new Array(5) @@ -377,3 +397,11 @@ test('import css in less', async () => { expect(await getColor('.css-in-less')).toBe('yellow') expect(await getColor('.css-in-less-2')).toBe('blue') }) + +test("relative path rewritten in Less's data-uri", async () => { + // relative path passed to Less's data-uri is rewritten to absolute, + // the Less inlines it + expect(await getBg('.form-box-data-uri')).toMatch( + /^url\("data:image\/svg\+xml,%3Csvg/ + ) +}) diff --git a/packages/playground/css/__tests__/postcss-plugins-different-dir.spec.ts b/packages/playground/css/__tests__/postcss-plugins-different-dir.spec.ts index 19e9a43ae4ff6e..8bedc26ee354c8 100644 --- a/packages/playground/css/__tests__/postcss-plugins-different-dir.spec.ts +++ b/packages/playground/css/__tests__/postcss-plugins-different-dir.spec.ts @@ -1,10 +1,10 @@ -import { getColor, getBgColor } from '../../testUtils' +import { getColor, getBgColor, ports } from '../../testUtils' import { createServer } from 'vite' import path from 'path' // Regression test for https://github.com/vitejs/vite/issues/4000 test('postcss plugins in different dir', async () => { - const port = 5006 + const port = ports['css/postcss-plugins-different-dir'] const server = await createServer({ root: path.join(__dirname, '..', '..', 'tailwind'), logLevel: 'silent', diff --git a/packages/playground/css/charset.css b/packages/playground/css/charset.css new file mode 100644 index 00000000000000..5c42b279f8404c --- /dev/null +++ b/packages/playground/css/charset.css @@ -0,0 +1,5 @@ +@charset "utf-8"; + +.utf8 { + color: green; +} diff --git a/packages/playground/css/folder with space/ok.png b/packages/playground/css/folder with space/ok.png new file mode 100644 index 00000000000000..a8d1e52510c41c Binary files /dev/null and b/packages/playground/css/folder with space/ok.png differ diff --git a/packages/playground/css/folder with space/space.css b/packages/playground/css/folder with space/space.css new file mode 100644 index 00000000000000..55a8532da32a94 --- /dev/null +++ b/packages/playground/css/folder with space/space.css @@ -0,0 +1,5 @@ +.import-with-space { + color: green; + background: url(spacefolder/ok.png); + background-position: center; +} diff --git a/packages/playground/css/imported.css b/packages/playground/css/imported.css index 65743d08b932a7..7d582995fab9fd 100644 --- a/packages/playground/css/imported.css +++ b/packages/playground/css/imported.css @@ -1,4 +1,5 @@ @import './imported-at-import.css'; +@import 'spacefolder/space.css'; .imported { color: green; diff --git a/packages/playground/css/index.html b/packages/playground/css/index.html index a09d8e6e7c46aa..fef6a0be393748 100644 --- a/packages/playground/css/index.html +++ b/packages/playground/css/index.html @@ -10,6 +10,10 @@

CSS

@import in import from js: This should be purple

+

+ @import from file with space: This should be green and have a background + image +

Imported css string:


   

@@ -45,6 +49,10 @@ 

CSS

Imported Less string:


 
+  
+ tests Less's `data-uri()` function with relative image paths +
+

Stylus: This should be blue

Stylus additionalData: This should be orange @@ -85,6 +93,12 @@

CSS


 
+  

Inline CSS module:

+

+
+  

CSS with @charset:

+

+
   

@import dependency w/ style enrtrypoints: this should be purple

@@ -101,7 +115,7 @@

CSS

- Url separation preservation: should have valid background-image + URL separation preservation: should have valid background-image

Inlined import - this should NOT be red.

diff --git a/packages/playground/css/inline.module.css b/packages/playground/css/inline.module.css new file mode 100644 index 00000000000000..9566e21e2cd1af --- /dev/null +++ b/packages/playground/css/inline.module.css @@ -0,0 +1,3 @@ +.apply-color-inline { + color: turquoise; +} diff --git a/packages/playground/css/less.less b/packages/playground/css/less.less index 69ffa830862014..49cbd3c3bb336e 100644 --- a/packages/playground/css/less.less +++ b/packages/playground/css/less.less @@ -1,6 +1,9 @@ @import '@/nested/nested'; @import './nested/css-in-less.less'; +// Test data-uri calls with relative images. +@import './less/components/form.less'; + @color: blue; .less { diff --git a/packages/playground/css/less/components/form.less b/packages/playground/css/less/components/form.less new file mode 100644 index 00000000000000..feaaea94ce1bba --- /dev/null +++ b/packages/playground/css/less/components/form.less @@ -0,0 +1,4 @@ +.form-box-data-uri { + // data-uri() calls with relative paths should be replaced just like urls. + background-image: data-uri('../images/backgrounds/form-select.svg'); +} diff --git a/packages/playground/css/less/images/backgrounds/form-select.svg b/packages/playground/css/less/images/backgrounds/form-select.svg new file mode 100644 index 00000000000000..8aaf69c09e03f4 --- /dev/null +++ b/packages/playground/css/less/images/backgrounds/form-select.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/playground/css/main.js b/packages/playground/css/main.js index 6edd840a87c5e7..0d03aafbf0ec7f 100644 --- a/packages/playground/css/main.js +++ b/packages/playground/css/main.js @@ -38,6 +38,12 @@ text( JSON.stringify(composesPathResolvingMod, null, 2) ) +import inlineMod from './inline.module.css?inline' +text('.modules-inline', inlineMod) + +import charset from './charset.css' +text('.charset-css', charset) + import './dep.css' import './glob-dep.css' diff --git a/packages/playground/css/postcss-caching/css.spec.ts b/packages/playground/css/postcss-caching/css.spec.ts index 6c85d127003680..e8ba73154b6bc8 100644 --- a/packages/playground/css/postcss-caching/css.spec.ts +++ b/packages/playground/css/postcss-caching/css.spec.ts @@ -1,9 +1,9 @@ -import { getColor } from '../../testUtils' +import { getColor, ports } from '../../testUtils' import { createServer } from 'vite' import path from 'path' test('postcss config', async () => { - const port = 5005 + const port = ports['css/postcss-caching'] const startServer = async (root) => { const server = await createServer({ root, diff --git a/packages/playground/css/vite.config.js b/packages/playground/css/vite.config.js index 53d001d8387989..639a1302debb88 100644 --- a/packages/playground/css/vite.config.js +++ b/packages/playground/css/vite.config.js @@ -9,7 +9,8 @@ module.exports = { }, resolve: { alias: { - '@': __dirname + '@': __dirname, + spacefolder: __dirname + '/folder with space' } }, css: { diff --git a/packages/playground/dynamic-import/__tests__/dynamic-import.spec.ts b/packages/playground/dynamic-import/__tests__/dynamic-import.spec.ts index 9f8276d5e4d855..c7157ef4652ec6 100644 --- a/packages/playground/dynamic-import/__tests__/dynamic-import.spec.ts +++ b/packages/playground/dynamic-import/__tests__/dynamic-import.spec.ts @@ -8,6 +8,10 @@ test('should load literal dynamic import', async () => { test('should load full dynamic import from public', async () => { await page.click('.qux') await untilUpdated(() => page.textContent('.view'), 'Qux view', true) + // No warning should be logged as we are using @vite-ignore + expect( + serverLogs.some((log) => log.includes('cannot be analyzed by vite')) + ).toBe(false) }) test('should load data URL of `blob:`', async () => { diff --git a/packages/playground/dynamic-import/nested/index.js b/packages/playground/dynamic-import/nested/index.js index 1a118ecc79051b..5518c56a35a2cc 100644 --- a/packages/playground/dynamic-import/nested/index.js +++ b/packages/playground/dynamic-import/nested/index.js @@ -35,7 +35,7 @@ document.querySelector('.mxd2').addEventListener('click', async () => { const test = { jss: '../mxd.js' } const ttest = test const view = 'mxd' - const { default: mxdDynamic } = await import(test.jss) + const { default: mxdDynamic } = await import(/*@vite-ignore*/ test.jss) text('.view', mxdStatic === mxdDynamic) }) diff --git a/packages/playground/fs-serve/__tests__/fs-serve.spec.ts b/packages/playground/fs-serve/__tests__/fs-serve.spec.ts index c618186b9bcd64..eba1e441881710 100644 --- a/packages/playground/fs-serve/__tests__/fs-serve.spec.ts +++ b/packages/playground/fs-serve/__tests__/fs-serve.spec.ts @@ -23,6 +23,15 @@ describe('main', () => { expect(await page.textContent('.safe-fetch-status')).toBe('200') }) + test('safe fetch with special characters', async () => { + expect( + await page.textContent('.safe-fetch-subdir-special-characters') + ).toMatch('KEY=safe') + expect( + await page.textContent('.safe-fetch-subdir-special-characters-status') + ).toBe('200') + }) + test('unsafe fetch', async () => { expect(await page.textContent('.unsafe-fetch')).toMatch('403 Restricted') expect(await page.textContent('.unsafe-fetch-status')).toBe('403') @@ -33,6 +42,13 @@ describe('main', () => { expect(await page.textContent('.safe-fs-fetch-status')).toBe('200') }) + test('safe fs fetch with special characters', async () => { + expect(await page.textContent('.safe-fs-fetch-special-characters')).toBe( + stringified + ) + expect(await page.textContent('.safe-fs-fetch-status')).toBe('200') + }) + test('unsafe fs fetch', async () => { expect(await page.textContent('.unsafe-fs-fetch')).toBe('') expect(await page.textContent('.unsafe-fs-fetch-status')).toBe('403') diff --git a/packages/playground/fs-serve/root/src/index.html b/packages/playground/fs-serve/root/src/index.html index 9e4f728a593a91..951e14ad2cce91 100644 --- a/packages/playground/fs-serve/root/src/index.html +++ b/packages/playground/fs-serve/root/src/index.html @@ -11,6 +11,8 @@

Safe Fetch

Safe Fetch Subdirectory


 

+

+

 
 

Unsafe Fetch


@@ -19,6 +21,8 @@ 

Unsafe Fetch

Safe /@fs/ Fetch


 

+

+

 
 

Unsafe /@fs/ Fetch


@@ -56,6 +60,16 @@ 

Denied

text('.safe-fetch-subdir', JSON.stringify(data)) }) + // inside allowed dir, with special characters, safe fetch + fetch('/src/special%20characters%20%C3%A5%C3%A4%C3%B6/safe.txt') + .then((r) => { + text('.safe-fetch-subdir-special-characters-status', r.status) + return r.text() + }) + .then((data) => { + text('.safe-fetch-subdir-special-characters', JSON.stringify(data)) + }) + // outside of allowed dir, treated as unsafe fetch('/unsafe.txt') .then((r) => { @@ -92,6 +106,20 @@

Denied

console.error(e) }) + // not imported before, inside root with special characters, treated as safe + fetch( + '/@fs/' + + ROOT + + '/root/src/special%20characters%20%C3%A5%C3%A4%C3%B6/safe.json' + ) + .then((r) => { + text('.safe-fs-fetch-special-characters-status', r.status) + return r.json() + }) + .then((data) => { + text('.safe-fs-fetch-special-characters', JSON.stringify(data)) + }) + // .env, denied by default fetch('/@fs/' + ROOT + '/root/.env') .then((r) => { diff --git "a/packages/playground/fs-serve/root/src/special characters \303\245\303\244\303\266/safe.json" "b/packages/playground/fs-serve/root/src/special characters \303\245\303\244\303\266/safe.json" new file mode 100644 index 00000000000000..84f96593c10bad --- /dev/null +++ "b/packages/playground/fs-serve/root/src/special characters \303\245\303\244\303\266/safe.json" @@ -0,0 +1,3 @@ +{ + "msg": "safe" +} diff --git "a/packages/playground/fs-serve/root/src/special characters \303\245\303\244\303\266/safe.txt" "b/packages/playground/fs-serve/root/src/special characters \303\245\303\244\303\266/safe.txt" new file mode 100644 index 00000000000000..3f3d0607101642 --- /dev/null +++ "b/packages/playground/fs-serve/root/src/special characters \303\245\303\244\303\266/safe.txt" @@ -0,0 +1 @@ +KEY=safe diff --git a/packages/playground/glob-import/__tests__/glob-import.spec.ts b/packages/playground/glob-import/__tests__/glob-import.spec.ts index fff8d9fe202ebc..ebdf6c0ab29193 100644 --- a/packages/playground/glob-import/__tests__/glob-import.spec.ts +++ b/packages/playground/glob-import/__tests__/glob-import.spec.ts @@ -66,6 +66,12 @@ const rawResult = { } } +const relativeRawResult = { + '../glob-import/dir/baz.json': { + msg: 'baz' + } +} + test('should work', async () => { expect(await page.textContent('.result')).toBe( JSON.stringify(allResult, null, 2) @@ -81,6 +87,12 @@ test('import glob raw', async () => { ) }) +test('import relative glob raw', async () => { + expect(await page.textContent('.relative-glob-raw')).toBe( + JSON.stringify(relativeRawResult, null, 2) + ) +}) + if (!isBuild) { test('hmr for adding/removing files', async () => { addFile('dir/a.js', '') diff --git a/packages/playground/glob-import/index.html b/packages/playground/glob-import/index.html index 52d41b817a169c..64f456aeb4d6a2 100644 --- a/packages/playground/glob-import/index.html +++ b/packages/playground/glob-import/index.html @@ -1,6 +1,7 @@

 

 

+

 
 
 
+
+
diff --git a/packages/playground/hmr/__tests__/hmr.spec.ts b/packages/playground/hmr/__tests__/hmr.spec.ts
index 6ddc2345ae4fb4..7325c9fe47943a 100644
--- a/packages/playground/hmr/__tests__/hmr.spec.ts
+++ b/packages/playground/hmr/__tests__/hmr.spec.ts
@@ -160,4 +160,38 @@ if (!isBuild) {
     expect(textprev).not.toMatch('direct')
     expect(textpost).not.toMatch('direct')
   })
+
+  test('not loaded dynamic import', async () => {
+    await page.goto(viteTestUrl + '/dynamic-import/index.html')
+
+    let btn = await page.$('button')
+    expect(await btn.textContent()).toBe('Counter 0')
+    await btn.click()
+    expect(await btn.textContent()).toBe('Counter 1')
+
+    // Modifying `index.ts` triggers a page reload, as expected
+    editFile('dynamic-import/index.ts', (code) => code)
+    await page.waitForNavigation()
+    btn = await page.$('button')
+    expect(await btn.textContent()).toBe('Counter 0')
+
+    await btn.click()
+    expect(await btn.textContent()).toBe('Counter 1')
+
+    // #7561
+    // `dep.ts` defines `import.module.hot.accept` and has not been loaded.
+    // Therefore, modifying it has no effect (doesn't trigger a page reload).
+    // (Note that, a dynamic import that is never loaded and that does not
+    // define `accept.module.hot.accept` may wrongfully trigger a full page
+    // reload, see discussion at #7561.)
+    editFile('dynamic-import/dep.ts', (code) => code)
+    try {
+      await page.waitForNavigation({ timeout: 1000 })
+    } catch (err) {
+      const errMsg = 'page.waitForNavigation: Timeout 1000ms exceeded.'
+      expect(err.message.slice(0, errMsg.length)).toBe(errMsg)
+    }
+    btn = await page.$('button')
+    expect(await btn.textContent()).toBe('Counter 1')
+  })
 }
diff --git a/packages/playground/hmr/dynamic-import/dep.ts b/packages/playground/hmr/dynamic-import/dep.ts
new file mode 100644
index 00000000000000..aca649f226f770
--- /dev/null
+++ b/packages/playground/hmr/dynamic-import/dep.ts
@@ -0,0 +1,2 @@
+// This file is never loaded
+import.meta.hot.accept(() => {})
diff --git a/packages/playground/hmr/dynamic-import/index.html b/packages/playground/hmr/dynamic-import/index.html
new file mode 100644
index 00000000000000..f5290ad4f1e507
--- /dev/null
+++ b/packages/playground/hmr/dynamic-import/index.html
@@ -0,0 +1,2 @@
+
+
diff --git a/packages/playground/hmr/dynamic-import/index.ts b/packages/playground/hmr/dynamic-import/index.ts
new file mode 100644
index 00000000000000..0230140278989f
--- /dev/null
+++ b/packages/playground/hmr/dynamic-import/index.ts
@@ -0,0 +1,12 @@
+const btn = document.querySelector('button')
+let count = 0
+const update = () => {
+  btn.textContent = `Counter ${count}`
+}
+btn.onclick = () => {
+  count++
+  update()
+}
+function neverCalled() {
+  import('./dep')
+}
diff --git a/packages/playground/html/__tests__/html.spec.ts b/packages/playground/html/__tests__/html.spec.ts
index 66f537e5026361..834db1f6126cad 100644
--- a/packages/playground/html/__tests__/html.spec.ts
+++ b/packages/playground/html/__tests__/html.spec.ts
@@ -231,7 +231,7 @@ if (!isBuild) {
       await editFile('invalid.html', (content) => {
         return content.replace('
Good') }) - const content = await page.waitForSelector('text=Good Html') + const content = await page.waitForSelector('text=Good HTML') expect(content).toBeTruthy() }) }) diff --git a/packages/playground/html/invalid.html b/packages/playground/html/invalid.html index 5b5cf429687466..8acea73f16bdad 100644 --- a/packages/playground/html/invalid.html +++ b/packages/playground/html/invalid.html @@ -1 +1 @@ -
+
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 c8c85d8df9b806..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,8 +61,14 @@ test('dont add extension to directory name (./dir-with-ext.js/index.js)', async expect(await page.textContent('.dir-with-ext')).toMatch('[success]') }) -test('do not resolve to the `module` field if the importer is a `require` call', async () => { - expect(await page.textContent('.require-pkg-with-module-field')).toMatch( +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]' ) }) diff --git a/packages/playground/resolve/index.html b/packages/playground/resolve/index.html index 2c4ed7b9aa760c..2478c89b495f49 100644 --- a/packages/playground/resolve/index.html +++ b/packages/playground/resolve/index.html @@ -58,8 +58,17 @@

Resolve file name containing dot

Browser Field

fail

-

Don't resolve to the `module` field if the importer is a `require` call

-

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

@@ -171,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 ( @@ -184,8 +194,11 @@

resolve package that contains # in path

text('.browser', main) } - import { msg as requireButWithModuleFieldMsg } from 'require-pkg-with-module-field' - text('.require-pkg-with-module-field', requireButWithModuleFieldMsg) + 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 dda4476bc6ae82..4b8d497b3dbb27 100644 --- a/packages/playground/resolve/package.json +++ b/packages/playground/resolve/package.json @@ -12,7 +12,8 @@ "@babel/runtime": "^7.16.0", "es5-ext": "0.10.53", "normalize.css": "^8.0.1", - "require-pkg-with-module-field": "link:./require-pkg-with-module-field", + "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-module-field/dep.cjs b/packages/playground/resolve/require-pkg-with-browser-and-module-field/dep.cjs similarity index 100% rename from packages/playground/resolve/require-pkg-with-module-field/dep.cjs rename to packages/playground/resolve/require-pkg-with-browser-and-module-field/dep.cjs 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-module-field/package.json b/packages/playground/resolve/require-pkg-with-browser-and-module-field/package.json similarity index 68% rename from packages/playground/resolve/require-pkg-with-module-field/package.json rename to packages/playground/resolve/require-pkg-with-browser-and-module-field/package.json index e409343a7567d5..2a0419b331c407 100644 --- a/packages/playground/resolve/require-pkg-with-module-field/package.json +++ b/packages/playground/resolve/require-pkg-with-browser-and-module-field/package.json @@ -1,5 +1,5 @@ { - "name": "require-pkg-with-module-field", + "name": "require-pkg-with-browser-and-module-field", "private": true, "version": "1.0.0", "main": "./index.cjs", 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/require-pkg-with-module-field/index.cjs b/packages/playground/resolve/require-pkg-with-module-field/index.cjs deleted file mode 100644 index da215f306d1ac1..00000000000000 --- a/packages/playground/resolve/require-pkg-with-module-field/index.cjs +++ /dev/null @@ -1,8 +0,0 @@ -const dep = require('./dep.cjs') - -const msg = - dep === '1.111222233334444555566e+21' - ? '[success] require-pkg-with-module-field' - : '[failed] require-pkg-with-module-field' - -exports.msg = msg diff --git a/packages/playground/resolve/vite.config.js b/packages/playground/resolve/vite.config.js index 0550d1ecf6f044..c1282f4ffc789d 100644 --- a/packages/playground/resolve/vite.config.js +++ b/packages/playground/resolve/vite.config.js @@ -42,6 +42,9 @@ module.exports = { } ], optimizeDeps: { - include: ['require-pkg-with-module-field'] + 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 @@ + + + + + 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 @@ + + 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 [ + " - 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 [ + " + + + + + ", + ], + "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/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 index 51497a0f5ebadd..c7fd0d6c19e4bc 100644 --- a/packages/playground/worker/__tests__/es/es-worker.spec.ts +++ b/packages/playground/worker/__tests__/es/es-worker.spec.ts @@ -60,7 +60,7 @@ if (isBuild) { // assert correct files test('inlined code generation', async () => { const files = fs.readdirSync(assetsDir) - expect(files.length).toBe(20) + 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')) @@ -94,7 +94,7 @@ test('classic worker', async () => { test('emit chunk', async () => { expect(await page.textContent('.emti-chunk-worker')).toMatch( - '{"msg1":"module1","msg2":"module2","msg3":"module3"}' + '["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__/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 91% rename from packages/playground/worker/__tests__/worker.spec.ts rename to packages/playground/worker/__tests__/iife/worker.spec.ts index fc381467f6a4d2..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,8 +51,11 @@ 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'), + 'pong http://localhost:3000/iife/sub-worker.js?worker_file' + ) }) if (isBuild) { 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/emit-chunk-nested-worker.js b/packages/playground/worker/emit-chunk-nested-worker.js index dff0f5bc64c5ad..6cb72b9488cfaf 100644 --- a/packages/playground/worker/emit-chunk-nested-worker.js +++ b/packages/playground/worker/emit-chunk-nested-worker.js @@ -1,7 +1,28 @@ import SubWorker from './emit-chunk-sub-worker?worker' - const subWorker = new SubWorker() subWorker.onmessage = (event) => { - self.postMessage(event.data) + 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 index bd6b1f6e4f7419..5d20becc781dd7 100644 --- a/packages/playground/worker/emit-chunk-sub-worker.js +++ b/packages/playground/worker/emit-chunk-sub-worker.js @@ -1,6 +1,8 @@ -Promise.all([import('./modules/module2'), import('./modules/module3')]).then( - (data) => { - const _data = { ...data[0], ...data[1] } - self.postMessage(_data) - } -) +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 60289ff84d6a06..602aa3d06bfcac 100644 --- a/packages/playground/worker/index.html +++ b/packages/playground/worker/index.html @@ -1,3 +1,8 @@ +

worker template error match:

+ + const worker = new Worker(new URL('./worker.js', import.meta.url)) + +

format iife:

Expected values:
@@ -22,13 +27,13 @@

format iife:

- new Worker(new Url('./url-worker.js', import.meta.url), { type: 'module' }) + new Worker(new URL('./url-worker.js', import.meta.url), { type: 'module' }) .worker-import-meta-url

- new SharedWorker(new Url('./url-shared-worker.js', import.meta.url), { type: + new SharedWorker(new URL('./url-shared-worker.js', import.meta.url), { type: 'module' }) .shared-worker-import-meta-url

@@ -41,13 +46,13 @@

format iife:

- new Worker(new Url('./classic-worker.js', import.meta.url)) + new Worker(new URL('./classic-worker.js', import.meta.url)) .classic-worker

- new SharedWorker(new Url('./classic-shared-worker.js', import.meta.url), { + new SharedWorker(new URL('./classic-shared-worker.js', import.meta.url), { type: 'classic' }) .classic-shared-worker

@@ -57,7 +62,9 @@

format iife:

- worker emit chunk + worker emit chunk
+ module and worker:worker in worker file
+ module and worker:module in worker file
.emti-chunk-worker

@@ -68,6 +75,12 @@

+

+ module and worker:worker in simple file + .module-and-worker-worker +

+ +