From 9d7abe183c913e3a5c6b6194fcb4d01e996604c1 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Wed, 6 Jul 2022 02:06:18 +0900 Subject: [PATCH 01/10] feat: warn if watcher is not working on WSL2 --- docs/config/build-options.md | 7 +++ docs/config/server-options.md | 15 ++++- packages/vite/src/node/build.ts | 43 +++++++++---- packages/vite/src/node/server/index.ts | 42 ++++++++++--- packages/vite/src/node/watcher.ts | 83 ++++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 20 deletions(-) create mode 100644 packages/vite/src/node/watcher.ts diff --git a/docs/config/build-options.md b/docs/config/build-options.md index f2c9598f752ada..fb55bec3a73d78 100644 --- a/docs/config/build-options.md +++ b/docs/config/build-options.md @@ -193,3 +193,10 @@ Limit for chunk size warnings (in kbs). - **Default:** `null` Set to `{}` to enable rollup watcher. This is mostly used in cases that involve build-only plugins or integrations processes. + +::: warning Using Vite on Windows Subsystem for Linux (WSL) 2 + +There are cases that file system watching does not work with WSL2. +See [`server.watch`](./server-options.md#server-watch) for more details. + +::: diff --git a/docs/config/server-options.md b/docs/config/server-options.md index 6a43117f2ff164..e66337b9915073 100644 --- a/docs/config/server-options.md +++ b/docs/config/server-options.md @@ -167,8 +167,6 @@ The error that appears in the Browser when the fallback happens can be ignored. File system watcher options to pass on to [chokidar](https://github.com/paulmillr/chokidar#api). -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 @@ -186,6 +184,19 @@ export default defineConfig({ }) ``` +::: warning Using Vite on Windows Subsystem for Linux (WSL) 2 + +When running Vite on WSL2, if the project folder resides in a Windows filesystem, file system watching does not work without `{ usePolling: true }`. This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739) with the Windows filesystem. + +To make file system watching work, you could either: + +- **Recommended**: Move the project folder outside of a Windows filesystem. + - Accessing Windows filesystem from WSL2 is slow. Removing that overhead will improve performance. +- Set `{ usePolling: true }` + - Note that [`usePolling` leads to high CPU utilization](https://github.com/paulmillr/chokidar#performance). + +::: + ## server.middlewareMode - **Type:** `boolean` diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 973dcef199d8ee..181fcf7d199e1c 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -21,6 +21,7 @@ import commonjsPlugin from '@rollup/plugin-commonjs' import type { RollupCommonJSOptions } from 'types/commonjs' import type { RollupDynamicImportVarsOptions } from 'types/dynamicImportVars' import type { TransformOptions } from 'esbuild' +import { detectWhetherChokidarWithDefaultOptionWorks, isWSL2 } from './watcher' import type { InlineConfig, ResolvedConfig } from './config' import { isDepsOptimizerEnabled, resolveConfig } from './config' import { buildReporterPlugin } from './plugins/reporter' @@ -502,22 +503,44 @@ async function doBuild( } const watcherOptions = config.build.watch + const resolvedChokidarOptions = { + ignoreInitial: true, + ignorePermissionErrors: true, + ...watcherOptions.chokidar, + ignored: [ + '**/node_modules/**', + '**/.git/**', + ...(watcherOptions?.chokidar?.ignored || []) + ] + } + + if (isWSL2 && resolvedChokidarOptions.usePolling === undefined) { + detectWhetherChokidarWithDefaultOptionWorks(config.root).then( + ({ result, warning }) => { + if (result === false) { + config.logger.warn( + colors.yellow( + colors.bold(`(!) `) + + 'Default file system watching is not working with your setup due to the limitation of WSL2. ' + + 'Rebuild will not happen.' + + 'More information: https://vitejs.dev/config/server-options.html#server-watch' + ) + ) + } + if (warning) { + config.logger.warn(colors.yellow(warning)) + } + } + ) + } + const { watch } = await import('rollup') const watcher = watch({ ...rollupOptions, output, watch: { ...watcherOptions, - chokidar: { - ignoreInitial: true, - ignorePermissionErrors: true, - ...watcherOptions.chokidar, - ignored: [ - '**/node_modules/**', - '**/.git/**', - ...(watcherOptions?.chokidar?.ignored || []) - ] - } + chokidar: resolvedChokidarOptions } }) diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index d270c92bfd0e74..5385c3643c48a1 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -37,6 +37,7 @@ import { CLIENT_DIR } from '../constants' import type { Logger } from '../logger' import { printCommonServerUrls } from '../logger' import { invalidatePackageData } from '../packages' +import { detectWhetherChokidarWithDefaultOptionWorks, isWSL2 } from '../watcher' import type { PluginContainer } from './pluginContainer' import { createPluginContainer } from './pluginContainer' import type { WebSocketServer } from './ws' @@ -282,14 +283,8 @@ export async function createServer( ) const { middlewareMode } = serverConfig - const middlewares = connect() as Connect.Server - const httpServer = middlewareMode - ? null - : await resolveHttpServer(serverConfig, middlewares, httpsOptions) - const ws = createWebSocketServer(httpServer, config, httpsOptions) - const { ignored = [], ...watchOptions } = serverConfig.watch || {} - const watcher = chokidar.watch(path.resolve(root), { + const resolvedWatchOptions: chokidar.WatchOptions = { ignored: [ '**/.git/**', '**/node_modules/**', @@ -300,7 +295,38 @@ export async function createServer( ignorePermissionErrors: true, disableGlobbing: true, ...watchOptions - }) as FSWatcher + } + + if (isWSL2 && resolvedWatchOptions.usePolling === undefined) { + detectWhetherChokidarWithDefaultOptionWorks(root).then( + ({ result, warning }) => { + if (result === false) { + config.logger.warn( + colors.yellow( + colors.bold(`(!) `) + + 'Default file system watching is not working with your setup due to the limitation of WSL2. ' + + 'HMR and other features will not work. ' + + 'More information: https://vitejs.dev/config/server-options.html#server-watch' + ) + ) + } + if (warning) { + config.logger.warn(colors.yellow(warning)) + } + } + ) + } + + const middlewares = connect() as Connect.Server + const httpServer = middlewareMode + ? null + : await resolveHttpServer(serverConfig, middlewares, httpsOptions) + const ws = createWebSocketServer(httpServer, config, httpsOptions) + + const watcher = chokidar.watch( + path.resolve(root), + resolvedWatchOptions + ) as FSWatcher const moduleGraph: ModuleGraph = new ModuleGraph((url, ssr) => container.resolveId(url, undefined, { ssr }) diff --git a/packages/vite/src/node/watcher.ts b/packages/vite/src/node/watcher.ts new file mode 100644 index 00000000000000..921760efea0e07 --- /dev/null +++ b/packages/vite/src/node/watcher.ts @@ -0,0 +1,83 @@ +import fs from 'node:fs' +import os from 'node:os' +import path from 'node:path' +import chokidar from 'chokidar' + +/** + * returns `true` for WSL2 including docker running on WSL2 + * + * https://github.com/microsoft/WSL/issues/423#issuecomment-844418910 + */ +export const isWSL2 = (() => { + const release = os.release() + // Example: `5.10.102.1-microsoft-standard-WSL2` + if (release.includes('WSL2')) { + // "Docker Desktop for Windows with WSL2 backend" and "Docker installed in WSL" comes here too + return true + } + + // Windows Example: `10.0.19044` + // WSL1 Example: `4.4.0-19041-Microsoft` + // Docker Desktop for Windows with WSL2 backend Example: `5.10.76-linuxkit` + return false +})() + +/** + * returns `true` when it works, `false` when it doesn't, `undefined` when it failed to detect + */ +export const detectWhetherChokidarWithDefaultOptionWorks = ( + root: string, + timeout = 100 +): Promise<{ result: boolean | undefined; warning: string | undefined }> => + new Promise((resolve) => { + const id = ('' + performance.now()).replace(/\./g, '') + const tempFileShort = `.chokidardetector.${id}.txt` + const tempFile = path.resolve(root, tempFileShort) + + let wroteFile = false + + let timeoutId: NodeJS.Timeout + const w = chokidar.watch(root, { + depth: 1, + disableGlobbing: true, + ignoreInitial: true + }) + w.on('add', () => { + resolveWithCleanup(true) + }) + w.on('error', () => { + resolveWithCleanup(undefined) + }) + w.on('ready', () => { + fs.promises.writeFile(tempFile, 'detector', 'utf-8').then( + () => { + wroteFile = true + }, + () => { + resolveWithCleanup(undefined) + } + ) + timeoutId = setTimeout(() => { + resolveWithCleanup(false) + }, timeout) + }) + + let resolved = false + const resolveWithCleanup = async (result: boolean | undefined) => { + if (resolved) return + resolved = true + + clearTimeout(timeoutId) + await w.close() + + let warning: string | undefined + if (wroteFile) { + try { + await fs.promises.unlink(tempFile) + } catch { + warning = `Failed to remove temp file (${tempFileShort}). This file can be removed.` + } + } + resolve({ result, warning }) + } + }) From 84f71e3f40f084c4d774ffc98ef4777fe0086130 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 9 Jul 2022 23:23:11 +0900 Subject: [PATCH 02/10] fix: use edit event --- packages/vite/src/node/watcher.ts | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/vite/src/node/watcher.ts b/packages/vite/src/node/watcher.ts index 921760efea0e07..e111bb298697c8 100644 --- a/packages/vite/src/node/watcher.ts +++ b/packages/vite/src/node/watcher.ts @@ -26,10 +26,12 @@ export const isWSL2 = (() => { * returns `true` when it works, `false` when it doesn't, `undefined` when it failed to detect */ export const detectWhetherChokidarWithDefaultOptionWorks = ( - root: string, - timeout = 100 + root: string ): Promise<{ result: boolean | undefined; warning: string | undefined }> => new Promise((resolve) => { + const editWait = 100 + const detectWaitTimeout = 500 + const id = ('' + performance.now()).replace(/\./g, '') const tempFileShort = `.chokidardetector.${id}.txt` const tempFile = path.resolve(root, tempFileShort) @@ -42,24 +44,29 @@ export const detectWhetherChokidarWithDefaultOptionWorks = ( disableGlobbing: true, ignoreInitial: true }) - w.on('add', () => { + // add works with WSL2, but edit does not work + w.on('edit', () => { resolveWithCleanup(true) }) w.on('error', () => { resolveWithCleanup(undefined) }) w.on('ready', () => { - fs.promises.writeFile(tempFile, 'detector', 'utf-8').then( - () => { + ;(async () => { + try { + await fs.promises.writeFile(tempFile, 'detector', 'utf-8') wroteFile = true - }, - () => { + await new Promise((resolve) => setTimeout(resolve, editWait)) + // edit file + await fs.promises.writeFile(tempFile, 'detector2', 'utf-8') + } catch { resolveWithCleanup(undefined) } - ) + })() + timeoutId = setTimeout(() => { resolveWithCleanup(false) - }, timeout) + }, detectWaitTimeout) }) let resolved = false From 868808e22b8d48bdabfc38ebb38bcaeb719e9679 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sun, 10 Jul 2022 00:55:11 +0900 Subject: [PATCH 03/10] fix: use change --- packages/vite/src/node/watcher.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/watcher.ts b/packages/vite/src/node/watcher.ts index e111bb298697c8..0baecd9383bb0d 100644 --- a/packages/vite/src/node/watcher.ts +++ b/packages/vite/src/node/watcher.ts @@ -44,8 +44,8 @@ export const detectWhetherChokidarWithDefaultOptionWorks = ( disableGlobbing: true, ignoreInitial: true }) - // add works with WSL2, but edit does not work - w.on('edit', () => { + // add works with WSL2, but change does not work + w.on('change', () => { resolveWithCleanup(true) }) w.on('error', () => { From 7ff09162d105d2bb4e758158b1f8bf716dcba4ae Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sun, 10 Jul 2022 01:43:43 +0900 Subject: [PATCH 04/10] fix: give up detection The current detection somehow works with docker+wsl2, but it does not work with wsl2. --- packages/vite/src/node/build.ts | 27 +++----- packages/vite/src/node/server/index.ts | 26 +++----- packages/vite/src/node/utils.ts | 19 ++++++ packages/vite/src/node/watcher.ts | 90 -------------------------- 4 files changed, 37 insertions(+), 125 deletions(-) delete mode 100644 packages/vite/src/node/watcher.ts diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 181fcf7d199e1c..2dd78e0741f348 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -21,13 +21,12 @@ import commonjsPlugin from '@rollup/plugin-commonjs' import type { RollupCommonJSOptions } from 'types/commonjs' import type { RollupDynamicImportVarsOptions } from 'types/dynamicImportVars' import type { TransformOptions } from 'esbuild' -import { detectWhetherChokidarWithDefaultOptionWorks, isWSL2 } from './watcher' import type { InlineConfig, ResolvedConfig } from './config' import { isDepsOptimizerEnabled, resolveConfig } from './config' import { buildReporterPlugin } from './plugins/reporter' import { buildEsbuildPlugin } from './plugins/esbuild' import { terserPlugin } from './plugins/terser' -import { copyDir, emptyDir, lookupFile, normalizePath } from './utils' +import { copyDir, emptyDir, isWSL2, lookupFile, normalizePath } from './utils' import { manifestPlugin } from './plugins/manifest' import type { Logger } from './logger' import { dataURIPlugin } from './plugins/dataUri' @@ -515,22 +514,14 @@ async function doBuild( } if (isWSL2 && resolvedChokidarOptions.usePolling === undefined) { - detectWhetherChokidarWithDefaultOptionWorks(config.root).then( - ({ result, warning }) => { - if (result === false) { - config.logger.warn( - colors.yellow( - colors.bold(`(!) `) + - 'Default file system watching is not working with your setup due to the limitation of WSL2. ' + - 'Rebuild will not happen.' + - 'More information: https://vitejs.dev/config/server-options.html#server-watch' - ) - ) - } - if (warning) { - config.logger.warn(colors.yellow(warning)) - } - } + config.logger.warn( + colors.yellow( + colors.bold(`(!) `) + + 'Default file system watching might not work with your setup due to the limitation of WSL2. ' + + 'Rebuild will not happen when file system watching is not working. ' + + 'To suppress this warning, set true or false to "build.watch.usePolling". ' + + 'More information: https://vitejs.dev/config/server-options.html#server-watch' + ) ) } diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 5385c3643c48a1..4fae784f479c5a 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -17,6 +17,7 @@ import type { InlineConfig, ResolvedConfig } from '../config' import { isDepsOptimizerEnabled, resolveConfig } from '../config' import { isParentDirectory, + isWSL2, mergeConfig, normalizePath, resolveHostname @@ -37,7 +38,6 @@ import { CLIENT_DIR } from '../constants' import type { Logger } from '../logger' import { printCommonServerUrls } from '../logger' import { invalidatePackageData } from '../packages' -import { detectWhetherChokidarWithDefaultOptionWorks, isWSL2 } from '../watcher' import type { PluginContainer } from './pluginContainer' import { createPluginContainer } from './pluginContainer' import type { WebSocketServer } from './ws' @@ -298,22 +298,14 @@ export async function createServer( } if (isWSL2 && resolvedWatchOptions.usePolling === undefined) { - detectWhetherChokidarWithDefaultOptionWorks(root).then( - ({ result, warning }) => { - if (result === false) { - config.logger.warn( - colors.yellow( - colors.bold(`(!) `) + - 'Default file system watching is not working with your setup due to the limitation of WSL2. ' + - 'HMR and other features will not work. ' + - 'More information: https://vitejs.dev/config/server-options.html#server-watch' - ) - ) - } - if (warning) { - config.logger.warn(colors.yellow(warning)) - } - } + config.logger.warn( + colors.yellow( + colors.bold(`(!) `) + + 'Default file system watching might not work with your setup due to the limitation of WSL2. ' + + 'HMR and other features will not work when file system watching is not working. ' + + 'To suppress this warning, set true or false to "server.watch.usePolling". ' + + 'More information: https://vitejs.dev/config/server-options.html#server-watch' + ) ) } diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 0b0c205d80b9e4..fc9c1d59d1ab6e 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -1087,3 +1087,22 @@ export const isNonDriveRelativeAbsolutePath = (p: string): boolean => { if (!isWindows) return p.startsWith('/') return windowsDrivePathPrefixRE.test(p) } + +/** + * returns `true` for WSL2 including docker running on WSL2 + * + * https://github.com/microsoft/WSL/issues/423#issuecomment-844418910 + */ +export const isWSL2 = (() => { + const release = os.release() + // Example: `5.10.102.1-microsoft-standard-WSL2` + if (release.includes('WSL2')) { + // "Docker Desktop for Windows with WSL2 backend" and "Docker installed in WSL" comes here too + return true + } + + // Windows Example: `10.0.19044` + // WSL1 Example: `4.4.0-19041-Microsoft` + // Docker Desktop for Windows with WSL2 backend Example: `5.10.76-linuxkit` + return false +})() diff --git a/packages/vite/src/node/watcher.ts b/packages/vite/src/node/watcher.ts deleted file mode 100644 index 0baecd9383bb0d..00000000000000 --- a/packages/vite/src/node/watcher.ts +++ /dev/null @@ -1,90 +0,0 @@ -import fs from 'node:fs' -import os from 'node:os' -import path from 'node:path' -import chokidar from 'chokidar' - -/** - * returns `true` for WSL2 including docker running on WSL2 - * - * https://github.com/microsoft/WSL/issues/423#issuecomment-844418910 - */ -export const isWSL2 = (() => { - const release = os.release() - // Example: `5.10.102.1-microsoft-standard-WSL2` - if (release.includes('WSL2')) { - // "Docker Desktop for Windows with WSL2 backend" and "Docker installed in WSL" comes here too - return true - } - - // Windows Example: `10.0.19044` - // WSL1 Example: `4.4.0-19041-Microsoft` - // Docker Desktop for Windows with WSL2 backend Example: `5.10.76-linuxkit` - return false -})() - -/** - * returns `true` when it works, `false` when it doesn't, `undefined` when it failed to detect - */ -export const detectWhetherChokidarWithDefaultOptionWorks = ( - root: string -): Promise<{ result: boolean | undefined; warning: string | undefined }> => - new Promise((resolve) => { - const editWait = 100 - const detectWaitTimeout = 500 - - const id = ('' + performance.now()).replace(/\./g, '') - const tempFileShort = `.chokidardetector.${id}.txt` - const tempFile = path.resolve(root, tempFileShort) - - let wroteFile = false - - let timeoutId: NodeJS.Timeout - const w = chokidar.watch(root, { - depth: 1, - disableGlobbing: true, - ignoreInitial: true - }) - // add works with WSL2, but change does not work - w.on('change', () => { - resolveWithCleanup(true) - }) - w.on('error', () => { - resolveWithCleanup(undefined) - }) - w.on('ready', () => { - ;(async () => { - try { - await fs.promises.writeFile(tempFile, 'detector', 'utf-8') - wroteFile = true - await new Promise((resolve) => setTimeout(resolve, editWait)) - // edit file - await fs.promises.writeFile(tempFile, 'detector2', 'utf-8') - } catch { - resolveWithCleanup(undefined) - } - })() - - timeoutId = setTimeout(() => { - resolveWithCleanup(false) - }, detectWaitTimeout) - }) - - let resolved = false - const resolveWithCleanup = async (result: boolean | undefined) => { - if (resolved) return - resolved = true - - clearTimeout(timeoutId) - await w.close() - - let warning: string | undefined - if (wroteFile) { - try { - await fs.promises.unlink(tempFile) - } catch { - warning = `Failed to remove temp file (${tempFileShort}). This file can be removed.` - } - } - resolve({ result, warning }) - } - }) From e8598bf9ad95dc99eefcf1b65c988b4093a937de Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sun, 10 Jul 2022 02:06:51 +0900 Subject: [PATCH 05/10] docs: explain about wsl2 limitation more accurately --- docs/config/server-options.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/config/server-options.md b/docs/config/server-options.md index e66337b9915073..c83451db5a0e1e 100644 --- a/docs/config/server-options.md +++ b/docs/config/server-options.md @@ -186,12 +186,13 @@ export default defineConfig({ ::: warning Using Vite on Windows Subsystem for Linux (WSL) 2 -When running Vite on WSL2, if the project folder resides in a Windows filesystem, file system watching does not work without `{ usePolling: true }`. This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739) with the Windows filesystem. +When running Vite on WSL2 and a file is edited by Windows applications (non WSL2 process), file system watching does not work without `{ usePolling: true }`. +This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739). To make file system watching work, you could either: -- **Recommended**: Move the project folder outside of a Windows filesystem. - - Accessing Windows filesystem from WSL2 is slow. Removing that overhead will improve performance. +- **Recommended**: Use WSL2 applications to edit your files. + - Also it is recommended to move the project folder outside of a Windows filesystem. Accessing Windows filesystem from WSL2 is slow. Removing that overhead will improve performance. - Set `{ usePolling: true }` - Note that [`usePolling` leads to high CPU utilization](https://github.com/paulmillr/chokidar#performance). From fe4e7e68583e1798a6e1830b3d35ecaf8d6d6c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Mon, 11 Jul 2022 01:29:18 +0900 Subject: [PATCH 06/10] chore: update docs, thanks blu Co-authored-by: Bjorn Lu --- docs/config/server-options.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/config/server-options.md b/docs/config/server-options.md index c83451db5a0e1e..f8629e9a33a35c 100644 --- a/docs/config/server-options.md +++ b/docs/config/server-options.md @@ -186,14 +186,13 @@ export default defineConfig({ ::: warning Using Vite on Windows Subsystem for Linux (WSL) 2 -When running Vite on WSL2 and a file is edited by Windows applications (non WSL2 process), file system watching does not work without `{ usePolling: true }`. -This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739). +When running Vite on WSL2, file system watching does not work when a file is edited by Windows applications (non-WSL2 process). This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739). -To make file system watching work, you could either: +To fix it, you could either: - **Recommended**: Use WSL2 applications to edit your files. - - Also it is recommended to move the project folder outside of a Windows filesystem. Accessing Windows filesystem from WSL2 is slow. Removing that overhead will improve performance. -- Set `{ usePolling: true }` + - It is also recommended to move the project folder outside of a Windows filesystem. Accessing Windows filesystem from WSL2 is slow. Removing that overhead will improve performance. +- Set `{ usePolling: true }`. - Note that [`usePolling` leads to high CPU utilization](https://github.com/paulmillr/chokidar#performance). ::: From 0eda07177b87db379b1366c7f9a5273e927789b1 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Mon, 11 Jul 2022 01:40:37 +0900 Subject: [PATCH 07/10] refactor: extract as resolveChokidarOptions --- packages/vite/src/node/build.ts | 33 ++++++---------------- packages/vite/src/node/server/index.ts | 32 ++++------------------ packages/vite/src/node/watch.ts | 38 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 51 deletions(-) create mode 100644 packages/vite/src/node/watch.ts diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 2dd78e0741f348..4d23d572b10ac7 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -26,7 +26,7 @@ import { isDepsOptimizerEnabled, resolveConfig } from './config' import { buildReporterPlugin } from './plugins/reporter' import { buildEsbuildPlugin } from './plugins/esbuild' import { terserPlugin } from './plugins/terser' -import { copyDir, emptyDir, isWSL2, lookupFile, normalizePath } from './utils' +import { copyDir, emptyDir, lookupFile, normalizePath } from './utils' import { manifestPlugin } from './plugins/manifest' import type { Logger } from './logger' import { dataURIPlugin } from './plugins/dataUri' @@ -48,6 +48,7 @@ import type { PackageData } from './packages' import { watchPackageDataPlugin } from './packages' import { ensureWatchPlugin } from './plugins/ensureWatch' import { ESBUILD_MODULES_TARGET, VERSION } from './constants' +import { resolveChokidarOptions } from './watch' export interface BuildOptions { /** @@ -501,36 +502,18 @@ async function doBuild( output.push(buildOutputOptions(outputs)) } - const watcherOptions = config.build.watch - const resolvedChokidarOptions = { - ignoreInitial: true, - ignorePermissionErrors: true, - ...watcherOptions.chokidar, - ignored: [ - '**/node_modules/**', - '**/.git/**', - ...(watcherOptions?.chokidar?.ignored || []) - ] - } - - if (isWSL2 && resolvedChokidarOptions.usePolling === undefined) { - config.logger.warn( - colors.yellow( - colors.bold(`(!) `) + - 'Default file system watching might not work with your setup due to the limitation of WSL2. ' + - 'Rebuild will not happen when file system watching is not working. ' + - 'To suppress this warning, set true or false to "build.watch.usePolling". ' + - 'More information: https://vitejs.dev/config/server-options.html#server-watch' - ) - ) - } + const resolvedChokidarOptions = resolveChokidarOptions( + config.logger, + config.build.watch.chokidar, + 'build.watch.chokidar' + ) const { watch } = await import('rollup') const watcher = watch({ ...rollupOptions, output, watch: { - ...watcherOptions, + ...config.build.watch, chokidar: resolvedChokidarOptions } }) diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 4fae784f479c5a..2e24a907f88836 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -17,7 +17,6 @@ import type { InlineConfig, ResolvedConfig } from '../config' import { isDepsOptimizerEnabled, resolveConfig } from '../config' import { isParentDirectory, - isWSL2, mergeConfig, normalizePath, resolveHostname @@ -38,6 +37,7 @@ import { CLIENT_DIR } from '../constants' import type { Logger } from '../logger' import { printCommonServerUrls } from '../logger' import { invalidatePackageData } from '../packages' +import { resolveChokidarOptions } from '../watch' import type { PluginContainer } from './pluginContainer' import { createPluginContainer } from './pluginContainer' import type { WebSocketServer } from './ws' @@ -283,31 +283,11 @@ export async function createServer( ) const { middlewareMode } = serverConfig - const { ignored = [], ...watchOptions } = serverConfig.watch || {} - const resolvedWatchOptions: chokidar.WatchOptions = { - ignored: [ - '**/.git/**', - '**/node_modules/**', - '**/test-results/**', // Playwright - ...(Array.isArray(ignored) ? ignored : [ignored]) - ], - ignoreInitial: true, - ignorePermissionErrors: true, - disableGlobbing: true, - ...watchOptions - } - - if (isWSL2 && resolvedWatchOptions.usePolling === undefined) { - config.logger.warn( - colors.yellow( - colors.bold(`(!) `) + - 'Default file system watching might not work with your setup due to the limitation of WSL2. ' + - 'HMR and other features will not work when file system watching is not working. ' + - 'To suppress this warning, set true or false to "server.watch.usePolling". ' + - 'More information: https://vitejs.dev/config/server-options.html#server-watch' - ) - ) - } + const resolvedWatchOptions = resolveChokidarOptions( + config.logger, + { disableGlobbing: true, ...serverConfig.watch }, + 'server.watch' + ) const middlewares = connect() as Connect.Server const httpServer = middlewareMode diff --git a/packages/vite/src/node/watch.ts b/packages/vite/src/node/watch.ts new file mode 100644 index 00000000000000..e33070dac1212e --- /dev/null +++ b/packages/vite/src/node/watch.ts @@ -0,0 +1,38 @@ +import type { WatchOptions } from 'types/chokidar' +import colors from 'picocolors' +import type { Logger } from './logger' +import { isWSL2 } from './utils' + +export function resolveChokidarOptions( + logger: Logger, + options: WatchOptions | undefined, + optionName: string +): WatchOptions { + const { ignored = [], ...otherOptions } = options ?? {} + + const resolvedWatchOptions: WatchOptions = { + ignored: [ + '**/.git/**', + '**/node_modules/**', + '**/test-results/**', // Playwright + ...(Array.isArray(ignored) ? ignored : [ignored]) + ], + ignoreInitial: true, + ignorePermissionErrors: true, + ...otherOptions + } + + if (isWSL2 && resolvedWatchOptions.usePolling === undefined) { + logger.warn( + colors.yellow( + colors.bold(`(!) `) + + 'Default file system watching might not work with your setup due to the limitation of WSL2. ' + + 'HMR and other features will not work when file system watching is not working. ' + + `To suppress this warning, set true or false to "${optionName}.usePolling". ` + + 'More information: https://vitejs.dev/config/server-options.html#server-watch' + ) + ) + } + + return resolvedWatchOptions +} From 608181ce6ac7dbffceb3b8e18c47af1816c52e4b Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Mon, 11 Jul 2022 01:41:58 +0900 Subject: [PATCH 08/10] chore: tweak warning message Co-authored-by: Bjorn Lu --- packages/vite/src/node/watch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/watch.ts b/packages/vite/src/node/watch.ts index e33070dac1212e..1d0bcf762772ef 100644 --- a/packages/vite/src/node/watch.ts +++ b/packages/vite/src/node/watch.ts @@ -26,7 +26,7 @@ export function resolveChokidarOptions( logger.warn( colors.yellow( colors.bold(`(!) `) + - 'Default file system watching might not work with your setup due to the limitation of WSL2. ' + + 'Default file system watching might not work with your setup due to a limitation of WSL2. ' + 'HMR and other features will not work when file system watching is not working. ' + `To suppress this warning, set true or false to "${optionName}.usePolling". ` + 'More information: https://vitejs.dev/config/server-options.html#server-watch' From da90b2f4f73036acf2a87c3f74d9cc90bcbaab0e Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Fri, 12 Aug 2022 08:46:44 +0900 Subject: [PATCH 09/10] fix: remove warning --- packages/vite/src/node/build.ts | 4 +--- packages/vite/src/node/server/index.ts | 9 ++++----- packages/vite/src/node/utils.ts | 19 ------------------- packages/vite/src/node/watch.ts | 19 +------------------ 4 files changed, 6 insertions(+), 45 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index be4ce76dfe0c6a..174e5a33d9169a 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -506,9 +506,7 @@ async function doBuild( } const resolvedChokidarOptions = resolveChokidarOptions( - config.logger, - config.build.watch.chokidar, - 'build.watch.chokidar' + config.build.watch.chokidar ) const { watch } = await import('rollup') diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index c3451069d96790..ee58ca6564753c 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -301,11 +301,10 @@ export async function createServer( ) const { middlewareMode } = serverConfig - const resolvedWatchOptions = resolveChokidarOptions( - config.logger, - { disableGlobbing: true, ...serverConfig.watch }, - 'server.watch' - ) + const resolvedWatchOptions = resolveChokidarOptions({ + disableGlobbing: true, + ...serverConfig.watch + }) const middlewares = connect() as Connect.Server const httpServer = middlewareMode diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 930efec8e2dbf8..85f85adf3cf550 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -1144,22 +1144,3 @@ export const isNonDriveRelativeAbsolutePath = (p: string): boolean => { if (!isWindows) return p.startsWith('/') return windowsDrivePathPrefixRE.test(p) } - -/** - * returns `true` for WSL2 including docker running on WSL2 - * - * https://github.com/microsoft/WSL/issues/423#issuecomment-844418910 - */ -export const isWSL2 = (() => { - const release = os.release() - // Example: `5.10.102.1-microsoft-standard-WSL2` - if (release.includes('WSL2')) { - // "Docker Desktop for Windows with WSL2 backend" and "Docker installed in WSL" comes here too - return true - } - - // Windows Example: `10.0.19044` - // WSL1 Example: `4.4.0-19041-Microsoft` - // Docker Desktop for Windows with WSL2 backend Example: `5.10.76-linuxkit` - return false -})() diff --git a/packages/vite/src/node/watch.ts b/packages/vite/src/node/watch.ts index 1d0bcf762772ef..378610e28f3799 100644 --- a/packages/vite/src/node/watch.ts +++ b/packages/vite/src/node/watch.ts @@ -1,12 +1,7 @@ import type { WatchOptions } from 'types/chokidar' -import colors from 'picocolors' -import type { Logger } from './logger' -import { isWSL2 } from './utils' export function resolveChokidarOptions( - logger: Logger, - options: WatchOptions | undefined, - optionName: string + options: WatchOptions | undefined ): WatchOptions { const { ignored = [], ...otherOptions } = options ?? {} @@ -22,17 +17,5 @@ export function resolveChokidarOptions( ...otherOptions } - if (isWSL2 && resolvedWatchOptions.usePolling === undefined) { - logger.warn( - colors.yellow( - colors.bold(`(!) `) + - 'Default file system watching might not work with your setup due to a limitation of WSL2. ' + - 'HMR and other features will not work when file system watching is not working. ' + - `To suppress this warning, set true or false to "${optionName}.usePolling". ` + - 'More information: https://vitejs.dev/config/server-options.html#server-watch' - ) - ) - } - return resolvedWatchOptions } From 967f1b23de50a447e833fd0a5c1daa782599e6dc Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Fri, 12 Aug 2022 08:53:57 +0900 Subject: [PATCH 10/10] docs: mention about docker --- docs/config/server-options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config/server-options.md b/docs/config/server-options.md index c3a7b88acc50d4..5092622e5d9f5e 100644 --- a/docs/config/server-options.md +++ b/docs/config/server-options.md @@ -188,7 +188,7 @@ export default defineConfig({ ::: warning Using Vite on Windows Subsystem for Linux (WSL) 2 -When running Vite on WSL2, file system watching does not work when a file is edited by Windows applications (non-WSL2 process). This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739). +When running Vite on WSL2, file system watching does not work when a file is edited by Windows applications (non-WSL2 process). This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739). This also applies to running on Docker with a WSL2 backend. To fix it, you could either: