@intlayer/swc 9.2.0 → 9.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -79,6 +79,74 @@ Three import modes are supported:
|
|
|
79
79
|
| `dynamic` | `useDictionaryDynamic` | Dynamic `.mjs` import |
|
|
80
80
|
| `fetch` | `useDictionaryDynamic` | Fetch `.mjs` import |
|
|
81
81
|
|
|
82
|
+
### Field renaming (`build.minify`)
|
|
83
|
+
|
|
84
|
+
When the compiled dictionaries have been minified — every user-defined content field renamed to a short alphabetic alias — the plugin rewrites the matching source accesses so both sides keep agreeing:
|
|
85
|
+
|
|
86
|
+
**Before**
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const { title } = useIntlayer("about");
|
|
90
|
+
const content = useIntlayer("about");
|
|
91
|
+
content.section.subtitle;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**After**
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
const { d: title } = useIntlayer("about");
|
|
98
|
+
const content = useIntlayer("about");
|
|
99
|
+
content.b.a;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Destructuring (including nested patterns, local aliases and defaults), member chains, optional chaining, static computed accesses (`content["title"]`), array indexes (`content.list[0].title`) and signal-style accessors (`content().title`) are all handled. Dynamic accesses (`content[key]`) stop the rewrite, leaving the rest of the chain untouched.
|
|
103
|
+
|
|
104
|
+
The rename tables come from the `fieldRenameMap` option. Deciding _which_ fields are unused and _what_ alias each gets requires reading every component source file and rewriting the dictionary JSON — file I/O and cross-file state a per-file Wasm transform cannot do — so that analysis runs in Node (in `@intlayer/babel`, driven by `withIntlayer`) and only its result is handed to this plugin.
|
|
105
|
+
|
|
106
|
+
### Build reporting
|
|
107
|
+
|
|
108
|
+
The plugin transforms one file at a time with no cross-file state, so all it can report is a line per file. That is a tracing aid, not build output — the purge and minify summaries a build normally prints (which dictionaries were pruned, which fields were removed, what was partially minified) come from the Node-side pipeline and follow `log.mode` in `intlayer.config.*`, exactly as in a Vite build.
|
|
109
|
+
|
|
110
|
+
`logLevel` is therefore `"off"` unless you ask for tracing:
|
|
111
|
+
|
|
112
|
+
| Level | Output |
|
|
113
|
+
| --------- | --------------------------------------------------------------------------- |
|
|
114
|
+
| `"off"` | Nothing (default) |
|
|
115
|
+
| `"info"` | One line per transformed file: injected imports and renamed field count |
|
|
116
|
+
| `"debug"` | Everything above, plus skipped files and the emitted code of each transform |
|
|
117
|
+
|
|
118
|
+
With `next-intlayer`, set `INTLAYER_SWC_LOG_LEVEL=info` (or `debug`) to turn it on; `log.mode: "disabled"` silences it regardless.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Next.js compatibility
|
|
123
|
+
|
|
124
|
+
An SWC Wasm plugin can only be loaded by a host that speaks its `swc_ecma_ast`
|
|
125
|
+
schema. **Next.js 16.1.0 is the minimum**: it is the first release built on
|
|
126
|
+
SWC's forward-compatible plugin ABI, where the AST travels as self-describing
|
|
127
|
+
CBOR instead of rkyv, so one binary keeps working on later releases. Earlier
|
|
128
|
+
releases require an exact schema match and reject the plugin.
|
|
129
|
+
|
|
130
|
+
| Next.js | `swc_ecma_ast` | Plugin loads |
|
|
131
|
+
| ------- | -------------- | -------------- |
|
|
132
|
+
| 14.2.x | 0.112.7 | ❌ rkyv ABI |
|
|
133
|
+
| 15.5.x | 14.0.0 | ❌ rkyv ABI |
|
|
134
|
+
| 16.0.x | 16.0.0 | ❌ rkyv ABI |
|
|
135
|
+
| 16.1.x | 19.0.0 | ✅ exact match |
|
|
136
|
+
| 16.2.x | 20.0.1 | ✅ |
|
|
137
|
+
| 16.3.x | 25.0.0 | ✅ |
|
|
138
|
+
|
|
139
|
+
You do not have to check this yourself: `withIntlayer` from
|
|
140
|
+
[`next-intlayer`](https://www.npmjs.com/package/next-intlayer) reads the Next.js
|
|
141
|
+
version from your project and simply does not register the plugin below 16.1.0.
|
|
142
|
+
Those builds succeed, they just run without the bundle optimisation instead of
|
|
143
|
+
failing with `failed to invoke plugin`.
|
|
144
|
+
|
|
145
|
+
This is also why the crate pins `swc_core` to the `54.x` line rather than the
|
|
146
|
+
latest release: `54.x` is the newest `swc_core` still on `swc_ecma_ast` 19, the
|
|
147
|
+
schema Next.js 16.1 ships. Moving the pin forward would raise the minimum
|
|
148
|
+
supported Next.js version with it.
|
|
149
|
+
|
|
82
150
|
---
|
|
83
151
|
|
|
84
152
|
## Usage: Next.js / SWC Wasm plugin (recommended)
|
|
@@ -112,6 +180,8 @@ const nextConfig: NextConfig = {
|
|
|
112
180
|
replaceDictionaryEntry: false,
|
|
113
181
|
filesList: [], // empty = transform all files
|
|
114
182
|
dictionaryModeMap: {}, // per-key overrides, e.g. { "heavy-dict": "dynamic" }
|
|
183
|
+
fieldRenameMap: {}, // minified field aliases, e.g. { about: { title: { shortName: "a", children: {} } } }
|
|
184
|
+
logLevel: "off", // "off" | "info" | "debug"
|
|
115
185
|
},
|
|
116
186
|
],
|
|
117
187
|
],
|
|
@@ -148,8 +218,7 @@ fn my_transform(program: Program, file_path: &str) -> Program {
|
|
|
148
218
|
fetch_dictionaries_dir: "/project/.intlayer/fetch_dictionaries".into(),
|
|
149
219
|
import_mode: Some("static".into()),
|
|
150
220
|
replace_dictionary_entry: Some(false),
|
|
151
|
-
|
|
152
|
-
dictionary_mode_map: None,
|
|
221
|
+
..PluginConfig::default()
|
|
153
222
|
};
|
|
154
223
|
process_transform(program, config, file_path.into())
|
|
155
224
|
}
|
|
@@ -166,22 +235,34 @@ cargo build-wasip1 --release
|
|
|
166
235
|
cargo build --target wasm32-wasip1 --features plugin --release
|
|
167
236
|
```
|
|
168
237
|
|
|
238
|
+
Build through the alias, or at least through this crate's `.cargo/config.toml`:
|
|
239
|
+
it sets `--cfg=swc_ast_unknown` for `wasm32` targets, which is what opts the
|
|
240
|
+
binary into the forward-compatible ABI. Built without it, the plugin only loads
|
|
241
|
+
on hosts sharing its exact `swc_ecma_ast` version, and the first Next.js release
|
|
242
|
+
that adds an AST node breaks every build using it.
|
|
243
|
+
|
|
169
244
|
---
|
|
170
245
|
|
|
171
246
|
## Plugin configuration reference
|
|
172
247
|
|
|
173
248
|
All fields correspond to the JSON object passed as the second element of each `swcPlugins` tuple.
|
|
174
249
|
|
|
175
|
-
| Field | Type | Default | Description
|
|
176
|
-
| ------------------------ | ---------------------------------- | ---------- |
|
|
177
|
-
| `dictionariesDir` | `string` | required | Absolute path to compiled `.json` dictionaries
|
|
178
|
-
| `dictionariesEntryPath` | `string` | required | Absolute path to the generated entry `.mjs` file
|
|
179
|
-
| `dynamicDictionariesDir` | `string` | required | Absolute path for dynamic `.mjs` modules
|
|
180
|
-
| `fetchDictionariesDir` | `string` | required | Absolute path for fetch `.mjs` modules
|
|
181
|
-
| `importMode` | `"static" \| "dynamic" \| "fetch"` | `"static"` | Global import strategy
|
|
182
|
-
| `replaceDictionaryEntry` | `boolean` | `false` | Replace entry file with empty stubs
|
|
183
|
-
| `filesList` | `string[]` | `[]` | Allowlist of absolute file paths; empty = all files
|
|
184
|
-
| `dictionaryModeMap` | `Record<string, string>` | `{}` | Per-dictionary import mode overrides
|
|
250
|
+
| Field | Type | Default | Description |
|
|
251
|
+
| ------------------------ | ---------------------------------- | ---------- | ---------------------------------------------------- |
|
|
252
|
+
| `dictionariesDir` | `string` | required | Absolute path to compiled `.json` dictionaries |
|
|
253
|
+
| `dictionariesEntryPath` | `string` | required | Absolute path to the generated entry `.mjs` file |
|
|
254
|
+
| `dynamicDictionariesDir` | `string` | required | Absolute path for dynamic `.mjs` modules |
|
|
255
|
+
| `fetchDictionariesDir` | `string` | required | Absolute path for fetch `.mjs` modules |
|
|
256
|
+
| `importMode` | `"static" \| "dynamic" \| "fetch"` | `"static"` | Global import strategy |
|
|
257
|
+
| `replaceDictionaryEntry` | `boolean` | `false` | Replace entry file with empty stubs |
|
|
258
|
+
| `filesList` | `string[]` | `[]` | Allowlist of absolute file paths; empty = all files |
|
|
259
|
+
| `dictionaryModeMap` | `Record<string, string>` | `{}` | Per-dictionary import mode overrides |
|
|
260
|
+
| `nestingDictionaryKeys` | `string[]` | `[]` | Keys imported through their `nested/` companion |
|
|
261
|
+
| `extraCallers` | `ExtraCallerConfig[]` | `[]` | Compat-adapter callers to rewrite like `useIntlayer` |
|
|
262
|
+
| `fieldRenameMap` | `Record<string, FieldRenameMap>` | `{}` | Minified field aliases, per dictionary key |
|
|
263
|
+
| `logLevel` | `"off" \| "info" \| "debug"` | `"off"` | Build-time reporting verbosity |
|
|
264
|
+
|
|
265
|
+
`FieldRenameMap` is a recursive object mapping each original field name to `{ shortName: string; children: FieldRenameMap }`.
|
|
185
266
|
|
|
186
267
|
---
|
|
187
268
|
|
|
@@ -189,10 +270,29 @@ All fields correspond to the JSON object passed as the second element of each `s
|
|
|
189
270
|
|
|
190
271
|
The following symbols are exported by this crate:
|
|
191
272
|
|
|
192
|
-
- **`PluginConfig`** – configuration struct (mirrors the JSON options above).
|
|
273
|
+
- **`PluginConfig`** – configuration struct (mirrors the JSON options above). Implements `Default`, so `..PluginConfig::default()` keeps call sites stable as options are added.
|
|
274
|
+
- **`ExtraCallerConfig` / `NamespaceOptionConfig`** – compat-adapter caller descriptors.
|
|
275
|
+
- **`FieldRenameMap` / `FieldRenameNode`** – the minified field alias tables.
|
|
276
|
+
- **`LogLevel`** – build-time reporting verbosity.
|
|
193
277
|
- **`process_transform(program, cfg, filename) -> Program`** – core transform function; accepts and returns an SWC `Program` AST.
|
|
194
278
|
- **`normalize_path(path: &str) -> String`** – normalises Windows-style backslash paths to forward slashes for cross-platform path diffing.
|
|
195
279
|
|
|
280
|
+
### Crate layout
|
|
281
|
+
|
|
282
|
+
| Module | Responsibility |
|
|
283
|
+
| ------------------ | ------------------------------------------------------------ |
|
|
284
|
+
| `config` | Plugin option types and their wire format |
|
|
285
|
+
| `ast` | Small helpers for reading and building AST nodes |
|
|
286
|
+
| `paths` | Path normalisation and relative module specifiers |
|
|
287
|
+
| `packages` | Recognised package specifiers and generated-file conventions |
|
|
288
|
+
| `extra_caller` | Namespace resolution for compat-adapter callers |
|
|
289
|
+
| `field_rename` | Source-side content field renaming (`build.minify`) |
|
|
290
|
+
| `pre_pass` | Caller discovery and the file-level dynamic/static decision |
|
|
291
|
+
| `optimize` | Call-site and import-specifier rewriting |
|
|
292
|
+
| `imports` | Injection of the dictionary imports the rewrite created |
|
|
293
|
+
| `dictionary_entry` | Emptying of the generated dictionaries entry module |
|
|
294
|
+
| `logger` | Build-time reporting |
|
|
295
|
+
|
|
196
296
|
---
|
|
197
297
|
|
|
198
298
|
## Documentation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/swc",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A SWC plugin for Intlayer that transforms declaration files and provides internationalization features during the build process according to the Intlayer configuration.",
|
|
6
6
|
"keywords": [
|
|
Binary file
|