Skip to content

Commit 628540f

Browse files
authored
Turbopack: Add new webpack loader rule/condition syntax in config (#82857)
# This PR: - [x] Allow a condition to be specified inline within a `rule` - [x] Support `all`/`any`/`not` for conditions - [x] Simple flattening/optimization logic for the generated `RuleCondition` objects - [x] Unit test coverage of flattening logic - [x] Allow builtin conditions (see #82765) to be specified in condition objects, instead of requiring a separate syntax for them - [x] Update regex serialization logic in `packages/next/src/build/swc/index.ts` - [x] Make sure the updated syntax is fully reflected in the config schema and typedefs - [x] Emit collectibles for configuration issues instead of hard-failing with anyhow - [x] e2e test coverage # Remaining Work for Subsequent PRs - [ ] Remove the legacy `conditions` field from the `turbopack` config object - [ ] Remove the legacy built-in condition object syntax from rules: #83068 - [ ] Allow array values in the `turbopack.rules` object: #83138 - [ ] Update user-facing documentation This PR is the bulk of the work towards implementing the proposed new loader rule syntax: https://www.notion.so/vercel/Turbopack-loader-rule-syntax-254e06b059c4809096d1e7c9afad278c *(copied below)* # Loader Syntax Proposal ## Today (documented) [https://nextjs.org/docs/app/api-reference/config/next-config-js/turbopack#configuring-webpack-loaders](https://nextjs.org/docs/app/api-reference/config/next-config-js/turbopack#configuring-webpack-loaders) ```javascript module.exports = { turbopack: { rules: { // all matched rules apply, adding their loaders in order '*.svg': { loaders: ['@svgr/webpack'], as: '*.js', }, }, }, } ``` ## Today (undocumented) - User-defined conditions You can define custom `#`-prefixed “conditions” that can act as filters for rules. ```javascript module.exports = { turbopack: { rules: { '#svg-file': { loaders: ['@svgr/webpack'], // `as` is incompatible! There's no obvious glob to match against! }, }, conditions: { "#svg-file": { // this is an implicit "and"/"all": both path and content must match path: '*.svg', // can also be a RegExp content: /\<svg[^\>]*\>/, // can match the contents of the file! }, }, }, } ``` ## Today (undocumented) - Built-in Conditions These use a different syntax, and are provided by Next.js / Turbopack (are not user-defined). ```javascript module.exports = { turbopack: { rules: { // This will match svg files in the project that aren't from `node_modules` '*.svg': { // These object properties are evaluated in order, and the first match // used. The supported keys can be found here: // #82765 foreign: false, // causes us to bail out if node_modules are matched default: { loaders: ['@svgr/webpack'], as: '*.js', } }, }, }, } ``` ## Proposed - Remove (minor breaking change in Next 16, was undocumented) the `conditions` field from the `turbopack` config object. The benefit of a separate `conditions` field was that named conditions could be re-used across rules. But, there’s not much value in allowing condition re-use as the configuration file is JS and could implement re-use with local variables or functions. - The separate `conditions` field was also incompatible with the `as` field. - Add an optional `condition` field to each rule object. - Rules must be matched by a glob first (can be `*`) before the condition is checked. - This allows compatibility with `as`, since there’s always an obvious glob for that to match against. - Maintain support for `path` and `content` properties in `condition` objects. - These can be used with each other (as an implicit `all`) - Extend `condition` object with `{all: [...]}`, `{any: [...]}` , and `{not: ...}`. - Similar to webpack’s `{and: [...]}`, `{or: [...]}` and `{not: ...}` syntax: https://webpack.js.org/configuration/module/#condition - Our underlying `RuleCondition` enum already supports this, it’s just a matter of translating it from the JS object. - Allow conditions to be an object or a string. If it’s a string, require it to be a built-in condition (like `'foreign'` or `'browser'`). - Allow values in the rules object to either be objects (what we support today) or an array of objects. ```javascript module.exports = { turbopack: { rules: { // all matched rules apply, adding their loaders in order '*.svg': [ // this optionally can be an array of objects (shown here), or just an object { // this condition is matched after the glob condition: { all: [ { not: 'foreign' }, // excludes `node_modules` { path: /app\/.*\.svg/, content: /\<svg[^\>]*\>/ }, ], }, loaders: ['@svgr/webpack'], as: '*.js', }, ], }, }, } ```
1 parent efac8e2 commit 628540f

File tree

21 files changed

+938
-221
lines changed

21 files changed

+938
-221
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/next-core/src/next_client/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,11 @@ pub async fn get_client_module_options_context(
248248
let mut foreign_conditions = loader_conditions.clone();
249249
foreign_conditions.insert(WebpackLoaderBuiltinCondition::Foreign);
250250
let foreign_enable_webpack_loaders =
251-
webpack_loader_options(project_path.clone(), next_config, true, foreign_conditions).await?;
251+
webpack_loader_options(project_path.clone(), next_config, foreign_conditions).await?;
252252

253253
// Now creates a webpack rules that applies to all code.
254254
let enable_webpack_loaders =
255-
webpack_loader_options(project_path.clone(), next_config, false, loader_conditions).await?;
255+
webpack_loader_options(project_path.clone(), next_config, loader_conditions).await?;
256256

257257
let tree_shaking_mode_for_user_code = *next_config
258258
.tree_shaking_mode_for_user_code(next_mode.is_development())

0 commit comments

Comments
 (0)