Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: update WSL2 watch limitation explanation #8939

Merged
merged 11 commits into from Aug 13, 2022
7 changes: 7 additions & 0 deletions docs/config/build-options.md
Expand Up @@ -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.

:::
16 changes: 14 additions & 2 deletions docs/config/server-options.md
Expand Up @@ -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
Expand All @@ -186,6 +184,20 @@ 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).

To make file system watching work, 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 }`
- Note that [`usePolling` leads to high CPU utilization](https://github.com/paulmillr/chokidar#performance).
sapphi-red marked this conversation as resolved.
Show resolved Hide resolved

:::

## server.middlewareMode

- **Type:** `boolean`
Expand Down
36 changes: 25 additions & 11 deletions packages/vite/src/node/build.ts
Expand Up @@ -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, 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'
Expand Down Expand Up @@ -502,22 +502,36 @@ async function doBuild(
}

const watcherOptions = config.build.watch
const resolvedChokidarOptions = {
ignoreInitial: true,
ignorePermissionErrors: true,
...watcherOptions.chokidar,
ignored: [
'**/node_modules/**',
'**/.git/**',
...(watcherOptions?.chokidar?.ignored || [])
]
}
sapphi-red marked this conversation as resolved.
Show resolved Hide resolved

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. ' +
sapphi-red marked this conversation as resolved.
Show resolved Hide resolved
'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 { 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
}
})

Expand Down
34 changes: 26 additions & 8 deletions packages/vite/src/node/server/index.ts
Expand Up @@ -17,6 +17,7 @@ import type { InlineConfig, ResolvedConfig } from '../config'
import { isDepsOptimizerEnabled, resolveConfig } from '../config'
import {
isParentDirectory,
isWSL2,
mergeConfig,
normalizePath,
resolveHostname
Expand Down Expand Up @@ -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/**',
Expand All @@ -300,7 +295,30 @@ export async function createServer(
ignorePermissionErrors: true,
disableGlobbing: true,
...watchOptions
}) as FSWatcher
}

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 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 })
Expand Down
19 changes: 19 additions & 0 deletions packages/vite/src/node/utils.ts
Expand Up @@ -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
})()