diff --git a/docs/config/index.md b/docs/config/index.md index c141e7be88712f..3a7f355452c814 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -485,6 +485,23 @@ export default defineConfig(async ({ command, mode }) => { When running Vite on Windows Subsystem for Linux (WSL) 2, if the project folder resides in a Windows filesystem, you'll need to set this option to `{ usePolling: true }`. This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739) with the Windows filesystem. + The Vite server watcher skips `.git/` and `node_modules/` directories by default. If you want to watch a package inside `node_modules/`, you can pass a negated glob pattern to `server.watch.ignored`. That is: + + ```js + export default defineConfig({ + server: { + watch: { + ignored: ['!**/node_modules/your-package-name/**'] + } + }, + // The watched package must be excluded from optimization, + // so that it can appear in the dependency graph and trigger hot reload. + optimizeDeps: { + exclude: ['your-package-name'] + } + }) + ``` + ### server.middlewareMode - **Type:** `'ssr' | 'html'` @@ -657,6 +674,17 @@ export default defineConfig({ If disabled, all CSS in the entire project will be extracted into a single CSS file. +### build.cssTarget + +- **Type:** `string | string[]` +- **Default:** the same as [`build.target`](/config/#build-target) + + This options allows users to set a different browser target for CSS minification from the one used for JavaScript transpilation. + + It should only be used when you are targeting a non-mainstream browser. + One example is Android WeChat WebView, which supports most modern JavaScript features but not the [`#RGBA` hexadecimal color notation in CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#rgb_colors). + In this case, you need to set `build.cssTarget` to `chrome61` to prevent vite from transform `rgba()` colors into `#RGBA` hexadecimal notations. + ### build.sourcemap - **Type:** `boolean | 'inline' | 'hidden'` @@ -730,7 +758,7 @@ export default defineConfig({ - **Type:** `boolean` - **Default:** `true` if `outDir` is inside `root` - By default, Vite will empty the `outDir` on build if it is inside project root. It will emit a warning if `outDir` is outside of root to avoid accidentially removing important files. You can explicitly set this option to suppress the warning. This is also available via command line as `--emptyOutDir`. + By default, Vite will empty the `outDir` on build if it is inside project root. It will emit a warning if `outDir` is outside of root to avoid accidentally removing important files. You can explicitly set this option to suppress the warning. This is also available via command line as `--emptyOutDir`. ### build.brotliSize diff --git a/docs/guide/index.md b/docs/guide/index.md index dae44ce09b3910..43421f6b52b79a 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -20,6 +20,21 @@ You can learn more about the rationale behind the project in the [Why Vite](./wh - The default build targets browsers that support both [native ESM via script tags](https://caniuse.com/es6-module) and [native ESM dynamic import](https://caniuse.com/es6-module-dynamic-import). Legacy browsers can be supported via the official [@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) - see the [Building for Production](./build) section for more details. +## Trying Vite Online + +You can try Vite online on [StackBlitz](https://vite.new/). It runs the Vite-based build setup directly in the browser, so it is almost identical to the local setup but doesn't require installing anything on your machine. You can navigate to `vite.new/{template}` to select which framework to use. + +The supported template presets are: + +| JavaScript | TypeScript | +| :---: | :---: | +| [vanilla](https://vite.new/vanilla) | [vanilla-ts](https://vite.new/vanilla-ts) | +| [vue](https://vite.new/vue) | [vue-ts](https://vite.new/vue-ts) | +| [react](https://vite.new/react) | [react-ts](https://vite.new/react-ts) | +| [preact](https://vite.new/preact) | [preact-ts](https://vite.new/preact-ts) | +| [lit](https://vite.new/lit) | [lit-ts](https://vite.new/lit-ts) | +| [svelte](https://vite.new/svelte) | [svelte-ts](https://vite.new/svelte-ts) | + ## Scaffolding Your First Vite Project ::: tip Compatibility Note @@ -59,22 +74,7 @@ npm init vite@latest my-vue-app -- --template vue yarn create vite my-vue-app --template vue ``` -Supported template presets include: - -- `vanilla` -- `vanilla-ts` -- `vue` -- `vue-ts` -- `react` -- `react-ts` -- `preact` -- `preact-ts` -- `lit` -- `lit-ts` -- `svelte` -- `svelte-ts` - -See [create-vite](https://github.com/vitejs/vite/tree/main/packages/create-vite) for more details on each template. +See [create-vite](https://github.com/vitejs/vite/tree/main/packages/create-vite) for more details on each supported template: `vanilla`, `vanilla-ts`, `vue`, `vue-ts`, `react`, `react-ts`, `preact`, `preact-ts`, `lit`, `lit-ts`, `svelte`, `svelte-ts`. ## Community Templates diff --git a/packages/playground/css/__tests__/css.spec.ts b/packages/playground/css/__tests__/css.spec.ts index ad5d9f344813e4..010f028a14ea82 100644 --- a/packages/playground/css/__tests__/css.spec.ts +++ b/packages/playground/css/__tests__/css.spec.ts @@ -338,3 +338,14 @@ test('inlined', async () => { // should not insert css expect(await getColor('.inlined')).toBe('black') }) + +test('minify css', async () => { + if (!isBuild) { + return + } + + // should keep the rgba() syntax + const cssFile = findAssetFile(/index\.\w+\.css$/) + expect(cssFile).toMatch('rgba(') + expect(cssFile).not.toMatch('#ffff00b3') +}) diff --git a/packages/playground/css/main.js b/packages/playground/css/main.js index cd2d6fda9ac0d5..24a278c8687940 100644 --- a/packages/playground/css/main.js +++ b/packages/playground/css/main.js @@ -1,3 +1,5 @@ +import './minify.css' + import css from './imported.css' text('.imported-css', css) diff --git a/packages/playground/css/minify.css b/packages/playground/css/minify.css new file mode 100644 index 00000000000000..ada062407cdb38 --- /dev/null +++ b/packages/playground/css/minify.css @@ -0,0 +1,3 @@ +.test-minify { + color: rgba(255, 255, 0, 0.7); +} diff --git a/packages/playground/css/vite.config.js b/packages/playground/css/vite.config.js index d49dcf4207834d..e4dc8d5a9f265f 100644 --- a/packages/playground/css/vite.config.js +++ b/packages/playground/css/vite.config.js @@ -3,6 +3,9 @@ const path = require('path') * @type {import('vite').UserConfig} */ module.exports = { + build: { + cssTarget: 'chrome61' + }, resolve: { alias: { '@': __dirname diff --git a/packages/playground/ssr-html/__tests__/serve.js b/packages/playground/ssr-html/__tests__/serve.js new file mode 100644 index 00000000000000..5ba5724f2b7a94 --- /dev/null +++ b/packages/playground/ssr-html/__tests__/serve.js @@ -0,0 +1,36 @@ +// @ts-check +// this is automtically detected by scripts/jestPerTestSetup.ts and will replace +// the default e2e test serve behavior + +const path = require('path') + +const port = (exports.port = 9530) + +/** + * @param {string} root + * @param {boolean} isProd + */ +exports.serve = async function serve(root, isProd) { + const { createServer } = require(path.resolve(root, 'server.js')) + const { app, vite } = await createServer(root, isProd) + + return new Promise((resolve, reject) => { + try { + const server = app.listen(port, () => { + resolve({ + // for test teardown + async close() { + await new Promise((resolve) => { + server.close(resolve) + }) + if (vite) { + await vite.close() + } + } + }) + }) + } catch (e) { + reject(e) + } + }) +} diff --git a/packages/playground/ssr-html/__tests__/ssr-html.spec.ts b/packages/playground/ssr-html/__tests__/ssr-html.spec.ts new file mode 100644 index 00000000000000..e34b8a91fc3421 --- /dev/null +++ b/packages/playground/ssr-html/__tests__/ssr-html.spec.ts @@ -0,0 +1,39 @@ +import { port } from './serve' +import fetch from 'node-fetch' + +const url = `http://localhost:${port}` + +describe('injected inline scripts', () => { + test('no injected inline scripts are present', async () => { + await page.goto(url) + const inlineScripts = await page.$$eval('script', (nodes) => + nodes.filter((n) => !n.getAttribute('src') && n.innerHTML) + ) + expect(inlineScripts).toHaveLength(0) + }) + + test('injected script proxied correctly', async () => { + await page.goto(url) + const proxiedScripts = await page.$$eval('script', (nodes) => + nodes + .filter((n) => { + const src = n.getAttribute('src') + if (!src) return false + return src.includes('?html-proxy&index') + }) + .map((n) => n.getAttribute('src')) + ) + + // assert at least 1 proxied script exists + expect(proxiedScripts).not.toHaveLength(0) + + const scriptContents = await Promise.all( + proxiedScripts.map((src) => fetch(url + src).then((res) => res.text())) + ) + + // all proxied scripts return code + for (const code of scriptContents) { + expect(code).toBeTruthy() + } + }) +}) diff --git a/packages/playground/ssr-html/index.html b/packages/playground/ssr-html/index.html new file mode 100644 index 00000000000000..c37dcc7e366ae8 --- /dev/null +++ b/packages/playground/ssr-html/index.html @@ -0,0 +1,11 @@ + + +
+ + +