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

feat: use native runtime to import the config #19178

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ You can also explicitly specify a config file to use with the `--config` CLI opt
vite --config my-config.js
```

::: tip BUNDLING THE CONFIG
By default, Vite uses `esbuild` to bundle the config into a temporary file. This can cause issues when importing TypeScript files in a monorepo. If you encounter any issues with this approach, you can specify `--configLoader=runner` to use the module runner instead - it will not create a temporary config and will transform any files on the fly. Note that module runner doesn't support CJS in config files, but external CJS packages should work as usual.
::: tip CONFIG LOADING
By default, Vite uses `esbuild` to bundle the config into a temporary file and load it. This may cause issues when importing TypeScript files in a monorepo. If you encounter any issues with this approach, you can specify `--configLoader runner` to use the [module runner](/guide/api-environment-runtimes.html#modulerunner) instead, which will not create a temporary config and will transform any files on the fly. Note that module runner doesn't support CJS in config files, but external CJS packages should work as usual.

Alternatively, if you're using an environment that supports TypeScript (e.g. `node --experimental-strip-types`), or if you're only writing plain JavaScript, you can specify `--configLoader native` to use the environment's native runtime to load the config file. Note that updates to modules imported by the config file are not detected and hence would not auto-restart the Vite server.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latest Node.js versions have type stripping unflagged, maybe it would be worth mentioning.

:::

## Config Intellisense
Expand Down
38 changes: 19 additions & 19 deletions docs/guide/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@ vite [root]

#### Options

| Options | |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `--host [host]` | Specify hostname (`string`) |
| `--port <port>` | Specify port (`number`) |
| `--open [path]` | Open browser on startup (`boolean \| string`) |
| `--cors` | Enable CORS (`boolean`) |
| `--strictPort` | Exit if specified port is already in use (`boolean`) |
| `--force` | Force the optimizer to ignore the cache and re-bundle (`boolean`) |
| `-c, --config <file>` | Use specified config file (`string`) |
| `--base <path>` | Public base path (default: `/`) (`string`) |
| `-l, --logLevel <level>` | info \| warn \| error \| silent (`string`) |
| `--clearScreen` | Allow/disable clear screen when logging (`boolean`) |
| `--configLoader <loader>` | Use `bundle` to bundle the config with esbuild or `runner` (experimental) to process it on the fly (default: `bundle`) |
| `--profile` | Start built-in Node.js inspector (check [Performance bottlenecks](/guide/troubleshooting#performance-bottlenecks)) |
| `-d, --debug [feat]` | Show debug logs (`string \| boolean`) |
| `-f, --filter <filter>` | Filter debug logs (`string`) |
| `-m, --mode <mode>` | Set env mode (`string`) |
| `-h, --help` | Display available CLI options |
| `-v, --version` | Display version number |
| Options | |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--host [host]` | Specify hostname (`string`) |
| `--port <port>` | Specify port (`number`) |
| `--open [path]` | Open browser on startup (`boolean \| string`) |
| `--cors` | Enable CORS (`boolean`) |
| `--strictPort` | Exit if specified port is already in use (`boolean`) |
| `--force` | Force the optimizer to ignore the cache and re-bundle (`boolean`) |
| `-c, --config <file>` | Use specified config file (`string`) |
| `--base <path>` | Public base path (default: `/`) (`string`) |
| `-l, --logLevel <level>` | info \| warn \| error \| silent (`string`) |
| `--clearScreen` | Allow/disable clear screen when logging (`boolean`) |
| `--configLoader <loader>` | Use `bundle` to bundle the config with esbuild, or `runner` (experimental) to process it on the fly, or `native` (experimental) to load using the native runtime (default: `bundle`) |
| `--profile` | Start built-in Node.js inspector (check [Performance bottlenecks](/guide/troubleshooting#performance-bottlenecks)) |
| `-d, --debug [feat]` | Show debug logs (`string \| boolean`) |
| `-f, --filter <filter>` | Filter debug logs (`string`) |
| `-m, --mode <mode>` | Set env mode (`string`) |
| `-h, --help` | Display available CLI options |
| `-v, --version` | Display version number |

## Build

Expand Down
4 changes: 2 additions & 2 deletions packages/vite/src/node/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface GlobalCLIOptions {
l?: LogLevel
logLevel?: LogLevel
clearScreen?: boolean
configLoader?: 'bundle' | 'runner'
configLoader?: 'bundle' | 'runner' | 'native'
d?: boolean | string
debug?: boolean | string
f?: string
Expand Down Expand Up @@ -155,7 +155,7 @@ cli
.option('--clearScreen', `[boolean] allow/disable clear screen when logging`)
.option(
'--configLoader <loader>',
`[string] use 'bundle' to bundle the config with esbuild or 'runner' (experimental) to process it on the fly (default: bundle)`,
`[string] use 'bundle' to bundle the config with esbuild, or 'runner' (experimental) to process it on the fly, or 'native' (experimental) to load using the native runtime (default: bundle)`,
)
.option('-d, --debug [feat]', `[string | boolean] show debug logs`)
.option('-f, --filter <filter>', `[string] filter debug logs`)
Expand Down
30 changes: 24 additions & 6 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ export interface ResolvedWorkerOptions {
export interface InlineConfig extends UserConfig {
configFile?: string | false
/** @experimental */
configLoader?: 'bundle' | 'runner'
configLoader?: 'bundle' | 'runner' | 'native'
envFile?: false
forceOptimizeDeps?: boolean
}
Expand Down Expand Up @@ -1696,15 +1696,19 @@ export async function loadConfigFromFile(
configRoot: string = process.cwd(),
logLevel?: LogLevel,
customLogger?: Logger,
configLoader: 'bundle' | 'runner' = 'bundle',
configLoader: 'bundle' | 'runner' | 'native' = 'bundle',
): Promise<{
path: string
config: UserConfig
dependencies: string[]
} | null> {
if (configLoader !== 'bundle' && configLoader !== 'runner') {
if (
configLoader !== 'bundle' &&
configLoader !== 'runner' &&
configLoader !== 'native'
) {
throw new Error(
`Unsupported configLoader: ${configLoader}. Accepted values are 'bundle' and 'runner'.`,
`Unsupported configLoader: ${configLoader}. Accepted values are 'bundle', 'runner', and 'native'.`,
)
}

Expand Down Expand Up @@ -1735,7 +1739,11 @@ export async function loadConfigFromFile(

try {
const resolver =
configLoader === 'bundle' ? bundleAndLoadConfigFile : importConfigFile
configLoader === 'bundle'
? bundleAndLoadConfigFile
: configLoader === 'runner'
? runnerImportConfigFile
: nativeImportConfigFile
const { configExport, dependencies } = await resolver(resolvedPath)
debug?.(`config file loaded in ${getTime()}`)

Expand All @@ -1762,7 +1770,17 @@ export async function loadConfigFromFile(
}
}

async function importConfigFile(resolvedPath: string) {
async function nativeImportConfigFile(resolvedPath: string) {
const module = await import(
pathToFileURL(resolvedPath).href + '?t=' + Date.now()
)
return {
configExport: module.default,
dependencies: [],
}
}

async function runnerImportConfigFile(resolvedPath: string) {
const { module, dependencies } = await runnerImport<{
default: UserConfigExport
}>(resolvedPath)
Expand Down
23 changes: 22 additions & 1 deletion playground/config/__tests__/config.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { resolve } from 'node:path'
import { loadConfigFromFile } from 'vite'
import { expect, it } from 'vitest'
import { describe, expect, it } from 'vitest'

const [nvMajor, nvMinor] = process.versions.node.split('.').map(Number)
const isImportAttributesSupported =
Expand Down Expand Up @@ -48,3 +48,24 @@ it.runIf(isImportAttributesSupported)(
`)
},
)

describe('loadConfigFromFile with configLoader: native', () => {
const fixtureRoot = resolve(import.meta.dirname, '../packages/native-import')

it('imports a basic js config', async () => {
const result = await loadConfigFromFile(
{} as any,
resolve(fixtureRoot, 'basic.js'),
fixtureRoot,
undefined,
undefined,
'native',
)
expect(result.config).toMatchInlineSnapshot(`
{
"value": "works",
}
`)
expect(result.dependencies.length).toBe(0)
})
})
3 changes: 3 additions & 0 deletions playground/config/packages/native-import/basic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
value: 'works',
}
Loading