next.js
38fdf0c0 - Turbopack: Add import.meta.glob support (Vite compat) (#92640)

Commit
2 days ago
Turbopack: Add import.meta.glob support (Vite compat) (#92640) ## What? Adds support for [Vite's `import.meta.glob`](https://vite.dev/guide/features.html#glob-import) in Turbopack. This is a compile-time transform that resolves glob patterns into a map of module paths to lazy/eager imports. ## Why? This is a commonly used Vite feature for dynamically importing groups of files (e.g., all markdown files in a directory, all route modules matching a pattern). ## How? ### Core implementation (`import_meta_glob.rs`) 1. **Analysis phase**: `import.meta.glob` is recognized as a well-known function via `WellKnownFunctionKind::ImportMetaGlob`. When called, arguments are statically analyzed to extract patterns and options. 2. **File discovery**: Uses Turbopack's `read_glob` (with `Glob::can_match_in_directory` for efficient directory pruning) to find matching files. Negative patterns (prefixed with `!`) are applied via a separate `Glob` matcher. 3. **Virtual module**: Each unique `import.meta.glob()` call generates a virtual `ImportMetaGlobAsset` module that exports an object mapping file paths to either: - **Lazy mode** (default): `() => import('./path')` thunks — resolved with `EcmaScriptModulesReferenceSubType::DynamicImport` - **Eager mode**: Direct `require('./path')` results — resolved with `EcmaScriptModulesReferenceSubType::Import` 4. **Code generation**: The `import.meta.glob(...)` call site is replaced with `__turbopack_require__(virtual_module_id)`. ### Architecture - **`ImportMetaGlobAsset`** is the virtual module. It stores only the origin, patterns, and options — no `source` reference. - **`ImportMetaGlobAsset::map()`** is a `#[turbo_tasks::function]` that builds glob matchers, scans the filesystem, and resolves all matched files as ESM imports. Being a turbo-tasks function, the result is memoised. Both `references()` and `chunk_item_content()` call this single cached function. - **`ident()`** is derived from `AssetIdent::from_path(origin_path)` with a modifier encoding all glob options, so two `import.meta.glob()` calls with different options produce different module idents. - **Side effects**: Lazy mode → `SideEffectFree` (only exports thunks, nothing evaluated). Eager mode → `ModuleEvaluationIsSideEffectFree` (the virtual module itself has no side effects, but its synchronous requires trigger real module evaluations). ### Supported options | Option | Description | |--------|-------------| | `eager` | `boolean` — load modules synchronously (default: `false`) | | `import` | `string` — select a named export (e.g., `'default'`) | | `query` | `string` — append query to imports (e.g., `'?raw'`) | | `base` | `string` — base directory for glob scanning | ### Error handling Unsupported or invalid usage produces clear compile-time diagnostics (error code `TP1008`): - `as` option → "not supported, use `query` instead" - Unknown option keys → lists supported options - Non-constant `eager` → "must be a constant boolean" - Non-constant patterns → "must be string literals" ### Not supported (intentionally) - `import.meta.globEager()` (removed in Vite 3) — users should use `{ eager: true }` - `as` option (deprecated in Vite 5) — users should use `query` ## Test Plan - [x] **Turbopack execution test** (`turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/import-meta-glob/`) - Lazy mode, eager mode, named import (`import: 'default'`), negative patterns - [x] **Turbopack snapshot tests** (`turbopack/crates/turbopack-tests/tests/snapshot/import-meta/glob/`) - Lazy glob, eager glob, named import - Negative patterns (`!**/bar.js`) - Multiple patterns (`['./dir/*.js', './other/*.js']`) - [x] **Turbopack snapshot error tests** (`turbopack/crates/turbopack-tests/tests/snapshot/import-meta/glob-error/`) - `as` option error, non-constant `eager` error, unknown option error - [x] **Next.js e2e tests** (`test/e2e/import-meta-glob/`) - Lazy/eager/named import modules, negative patterns, multi-pattern - Passes in both dev (`next dev`) and production (`next build && next start`) modes - Skipped under webpack (`IS_WEBPACK_TEST=1`) since this is a Turbopack-only feature <!-- NEXT_JS_LLM_PR --> --------- Co-authored-by: Tobias Koppers <sokra@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Niklas Mischkulnig <mischnic@users.noreply.github.com>
Author
Parents
Loading