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.

:::
15 changes: 13 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,19 @@ 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).

To fix it, you could either:

- **Recommended**: Use WSL2 applications to edit your files.
- 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).

:::

## server.middlewareMode

- **Type:** `boolean`
Expand Down
21 changes: 9 additions & 12 deletions packages/vite/src/node/build.ts
Expand Up @@ -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 {
/**
Expand Down Expand Up @@ -501,23 +502,19 @@ async function doBuild(
output.push(buildOutputOptions(outputs))
}

const watcherOptions = config.build.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,
chokidar: {
ignoreInitial: true,
ignorePermissionErrors: true,
...watcherOptions.chokidar,
ignored: [
'**/node_modules/**',
'**/.git/**',
...(watcherOptions?.chokidar?.ignored || [])
]
}
...config.build.watch,
chokidar: resolvedChokidarOptions
}
})

Expand Down
24 changes: 11 additions & 13 deletions packages/vite/src/node/server/index.ts
Expand Up @@ -37,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'
Expand Down Expand Up @@ -282,25 +283,22 @@ export async function createServer(
)
const { middlewareMode } = serverConfig

const resolvedWatchOptions = resolveChokidarOptions(
config.logger,
{ disableGlobbing: true, ...serverConfig.watch },
'server.watch'
)

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), {
ignored: [
'**/.git/**',
'**/node_modules/**',
'**/test-results/**', // Playwright
...(Array.isArray(ignored) ? ignored : [ignored])
],
ignoreInitial: true,
ignorePermissionErrors: true,
disableGlobbing: true,
...watchOptions
}) as FSWatcher
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
})()
38 changes: 38 additions & 0 deletions 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 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
}