vite-legacy-pass-through 1.0.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/LICENSE +21 -0
- package/README.md +143 -0
- package/dist/index.cjs +52 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 el_jijuna
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# vite-legacy-pass-through ā”
|
|
2
|
+
|
|
3
|
+
> A Vite plugin that marks legacy libraries as external, preventing Rolldown from bundling them and causing CommonJS interop errors at runtime.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## š§© The story behind this plugin
|
|
8
|
+
|
|
9
|
+
This plugin was born out of a real-world headache while juggling a legacy component library and a newer one built on top of it.
|
|
10
|
+
|
|
11
|
+
The setup looked like this:
|
|
12
|
+
|
|
13
|
+
- šļø **lib-legacy** ā an older component library with `prop-types` as a dependency. Used directly inside a Vite-powered web app, everything worked perfectly fine.
|
|
14
|
+
- ⨠**lib-awesome** ā a newer library built to override and extend UI and functionality from `lib-legacy`. Its components imported from `lib-legacy`, added behaviour, and re-exported them.
|
|
15
|
+
|
|
16
|
+
The problem surfaced the moment **lib-awesome** was built with **Vite 8**. Because it imported components from `lib-legacy` and re-exported them, Rolldown pulled `prop-types` deep into the bundle. The output contained a file named something like `prop-types-a1b2c3d4.js` with a bare `require(...)` call ā which blew up at runtime in ESM environments:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
ReferenceError: require is not defined
|
|
20
|
+
at prop-types-a1b2c3d4.js:1:1
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
After a lot of reading about how Vite 8 and Rolldown handle module bundling and CJS/ESM interop, the cleanest escape hatch turned out to be telling Rolldown: *"don't touch lib-legacy ā let it pass through as-is."*
|
|
24
|
+
|
|
25
|
+
That's exactly what this plugin does.
|
|
26
|
+
|
|
27
|
+
```mermaid
|
|
28
|
+
flowchart TD
|
|
29
|
+
subgraph without["ā Without the plugin"]
|
|
30
|
+
A[lib-awesome] -->|imports & re-exports| B[lib-legacy]
|
|
31
|
+
B -->|has dependency| C[prop-types CJS]
|
|
32
|
+
A -->|build| D[Rolldown bundles everything]
|
|
33
|
+
D --> E["prop-types-a1b2c3d4.js\nā ļø require() call inside"]
|
|
34
|
+
E --> F["š„ ReferenceError: require is not defined"]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
subgraph with["ā
With vite-legacy-pass-through"]
|
|
38
|
+
G[lib-awesome] -->|imports & re-exports| H[lib-legacy]
|
|
39
|
+
H -->|has dependency| I[prop-types CJS]
|
|
40
|
+
G -->|build| J[Rolldown sees lib-legacy as external]
|
|
41
|
+
J --> K["lib-legacy stays as import statement\nā
no bundling, no require()"]
|
|
42
|
+
K --> L["š Works at runtime"]
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
> ā ļø **Important:** Rolldown does **not** recommend marking packages as external this way in library builds. Doing so shifts the module resolution responsibility entirely to the consumer ā they must have the library available in their environment. Use this plugin only when you understand that trade-off and the legacy library is guaranteed to be present at runtime.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## š¦ Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install -D vite-legacy-pass-through
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## š Usage
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
// vite.config.ts
|
|
62
|
+
import { defineConfig } from 'vite'
|
|
63
|
+
import { legacyPassThrough } from 'vite-legacy-pass-through'
|
|
64
|
+
|
|
65
|
+
export default defineConfig({
|
|
66
|
+
plugins: [
|
|
67
|
+
legacyPassThrough({
|
|
68
|
+
libs: ['lib-legacy'],
|
|
69
|
+
}),
|
|
70
|
+
],
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Multiple libraries:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
legacyPassThrough({
|
|
78
|
+
libs: ['lib-legacy', 'another-legacy-lib'],
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
With logging enabled (useful during development to confirm which imports are being bypassed):
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
legacyPassThrough({
|
|
86
|
+
libs: ['lib-legacy'],
|
|
87
|
+
showLog: true,
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Output when `showLog: true`:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
[vite-legacy-pass-through] Resolving: lib-legacy/components/Button
|
|
95
|
+
[vite-legacy-pass-through] Resolving: lib-legacy/utils/format
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## āļø Options
|
|
101
|
+
|
|
102
|
+
| Option | Type | Required | Default | Description |
|
|
103
|
+
|---|---|---|---|---|
|
|
104
|
+
| `libs` | `string[]` | Yes | ā | List of library names to mark as external. Empty strings are ignored. Must have at least one valid entry. |
|
|
105
|
+
| `showLog` | `boolean` | No | `false` | Logs each resolved import to the console. |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## š How it works
|
|
110
|
+
|
|
111
|
+
The plugin hooks into Vite's `resolveId` phase with `enforce: 'pre'` ā meaning it runs before any other plugin ā and marks any import whose path starts with `<lib>/` as external. Rolldown then skips bundling it entirely and leaves the import statement untouched in the output.
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
import Button from 'lib-legacy/components/Button'
|
|
115
|
+
ā resolveId hook intercepts
|
|
116
|
+
{ id: 'lib-legacy/components/Button', external: true }
|
|
117
|
+
ā Rolldown skips it, output keeps the import
|
|
118
|
+
import Button from 'lib-legacy/components/Button'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
> Note: bare imports (`import 'lib-legacy'` without a subpath) are **not** affected ā only subpath imports (`lib-legacy/...`) are matched. This is intentional to avoid over-matching.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## š¤ When to use this
|
|
126
|
+
|
|
127
|
+
- You are building a library that imports and re-exports from a legacy package.
|
|
128
|
+
- That legacy package uses CommonJS internally (e.g. `prop-types`, older UI kits).
|
|
129
|
+
- Vite 8 / Rolldown is wrapping those CJS modules into the bundle and generating `require()` calls that break in ESM environments.
|
|
130
|
+
- The legacy package will be available at runtime in the consumer's environment (i.e. it is a peer or runtime dependency, not something you need to ship inside your bundle).
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## š Requirements
|
|
135
|
+
|
|
136
|
+
- **Vite**: `^8.0.0`
|
|
137
|
+
- **Node.js**: `>=18`
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## š License
|
|
142
|
+
|
|
143
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
default: () => index_default,
|
|
24
|
+
legacyPassThrough: () => legacyPassThrough
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
function legacyPassThrough({ libs, showLog } = { libs: [] }) {
|
|
28
|
+
const validLibs = libs.filter((lib) => lib.trim() !== "");
|
|
29
|
+
if (!validLibs.length) {
|
|
30
|
+
throw new Error('The "libs" option must be a non-empty array for the legacyPassThrough plugin.');
|
|
31
|
+
}
|
|
32
|
+
const prefixes = validLibs.map((lib) => `${lib}/`);
|
|
33
|
+
return {
|
|
34
|
+
name: "vite-legacy-pass-through",
|
|
35
|
+
enforce: "pre",
|
|
36
|
+
resolveId(source) {
|
|
37
|
+
if (prefixes.some((prefix) => source.startsWith(prefix))) {
|
|
38
|
+
if (showLog) {
|
|
39
|
+
console.log(`[vite-legacy-pass-through] Resolving: ${source}`);
|
|
40
|
+
}
|
|
41
|
+
return { id: source, external: true };
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
var index_default = legacyPassThrough;
|
|
48
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
49
|
+
0 && (module.exports = {
|
|
50
|
+
legacyPassThrough
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Plugin } from 'vite'\n\nexport interface LegacyPassThroughOptions {\n libs: string[]\n showLog?: boolean\n}\n\nexport function legacyPassThrough({ libs, showLog }: LegacyPassThroughOptions = { libs: [] }): Plugin {\n const validLibs = libs.filter(lib => lib.trim() !== '')\n\n if (!validLibs.length) {\n throw new Error('The \"libs\" option must be a non-empty array for the legacyPassThrough plugin.')\n }\n\n const prefixes = validLibs.map(lib => `${lib}/`)\n\n return {\n name: 'vite-legacy-pass-through',\n enforce: 'pre',\n resolveId(source) {\n if (prefixes.some(prefix => source.startsWith(prefix))) {\n if (showLog) {\n console.log(`[vite-legacy-pass-through] Resolving: ${source}`)\n }\n return { id: source, external: true }\n }\n return null\n },\n }\n}\n\nexport default legacyPassThrough\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,SAAS,kBAAkB,EAAE,MAAM,QAAQ,IAA8B,EAAE,MAAM,CAAC,EAAE,GAAW;AACpG,QAAM,YAAY,KAAK,OAAO,SAAO,IAAI,KAAK,MAAM,EAAE;AAEtD,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,+EAA+E;AAAA,EACjG;AAEA,QAAM,WAAW,UAAU,IAAI,SAAO,GAAG,GAAG,GAAG;AAE/C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU,QAAQ;AAChB,UAAI,SAAS,KAAK,YAAU,OAAO,WAAW,MAAM,CAAC,GAAG;AACtD,YAAI,SAAS;AACX,kBAAQ,IAAI,yCAAyC,MAAM,EAAE;AAAA,QAC/D;AACA,eAAO,EAAE,IAAI,QAAQ,UAAU,KAAK;AAAA,MACtC;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
interface LegacyPassThroughOptions {
|
|
4
|
+
libs: string[];
|
|
5
|
+
showLog?: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare function legacyPassThrough({ libs, showLog }?: LegacyPassThroughOptions): Plugin;
|
|
8
|
+
|
|
9
|
+
export { type LegacyPassThroughOptions, legacyPassThrough as default, legacyPassThrough };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
interface LegacyPassThroughOptions {
|
|
4
|
+
libs: string[];
|
|
5
|
+
showLog?: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare function legacyPassThrough({ libs, showLog }?: LegacyPassThroughOptions): Plugin;
|
|
8
|
+
|
|
9
|
+
export { type LegacyPassThroughOptions, legacyPassThrough as default, legacyPassThrough };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
function legacyPassThrough({ libs, showLog } = { libs: [] }) {
|
|
3
|
+
const validLibs = libs.filter((lib) => lib.trim() !== "");
|
|
4
|
+
if (!validLibs.length) {
|
|
5
|
+
throw new Error('The "libs" option must be a non-empty array for the legacyPassThrough plugin.');
|
|
6
|
+
}
|
|
7
|
+
const prefixes = validLibs.map((lib) => `${lib}/`);
|
|
8
|
+
return {
|
|
9
|
+
name: "vite-legacy-pass-through",
|
|
10
|
+
enforce: "pre",
|
|
11
|
+
resolveId(source) {
|
|
12
|
+
if (prefixes.some((prefix) => source.startsWith(prefix))) {
|
|
13
|
+
if (showLog) {
|
|
14
|
+
console.log(`[vite-legacy-pass-through] Resolving: ${source}`);
|
|
15
|
+
}
|
|
16
|
+
return { id: source, external: true };
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
var index_default = legacyPassThrough;
|
|
23
|
+
export {
|
|
24
|
+
index_default as default,
|
|
25
|
+
legacyPassThrough
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Plugin } from 'vite'\n\nexport interface LegacyPassThroughOptions {\n libs: string[]\n showLog?: boolean\n}\n\nexport function legacyPassThrough({ libs, showLog }: LegacyPassThroughOptions = { libs: [] }): Plugin {\n const validLibs = libs.filter(lib => lib.trim() !== '')\n\n if (!validLibs.length) {\n throw new Error('The \"libs\" option must be a non-empty array for the legacyPassThrough plugin.')\n }\n\n const prefixes = validLibs.map(lib => `${lib}/`)\n\n return {\n name: 'vite-legacy-pass-through',\n enforce: 'pre',\n resolveId(source) {\n if (prefixes.some(prefix => source.startsWith(prefix))) {\n if (showLog) {\n console.log(`[vite-legacy-pass-through] Resolving: ${source}`)\n }\n return { id: source, external: true }\n }\n return null\n },\n }\n}\n\nexport default legacyPassThrough\n"],"mappings":";AAOO,SAAS,kBAAkB,EAAE,MAAM,QAAQ,IAA8B,EAAE,MAAM,CAAC,EAAE,GAAW;AACpG,QAAM,YAAY,KAAK,OAAO,SAAO,IAAI,KAAK,MAAM,EAAE;AAEtD,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,+EAA+E;AAAA,EACjG;AAEA,QAAM,WAAW,UAAU,IAAI,SAAO,GAAG,GAAG,GAAG;AAE/C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU,QAAQ;AAChB,UAAI,SAAS,KAAK,YAAU,OAAO,WAAW,MAAM,CAAC,GAAG;AACtD,YAAI,SAAS;AACX,kBAAQ,IAAI,yCAAyC,MAAM,EAAE;AAAA,QAC/D;AACA,eAAO,EAAE,IAAI,QAAQ,UAAU,KAAK;AAAA,MACtC;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vite-legacy-pass-through",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vite plugin to pass through legacy assets without transformation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"test:watch": "vitest",
|
|
30
|
+
"prepublishOnly": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"vite",
|
|
34
|
+
"plugin",
|
|
35
|
+
"legacy",
|
|
36
|
+
"pass-through",
|
|
37
|
+
"rolldown",
|
|
38
|
+
"external",
|
|
39
|
+
"prop-types"
|
|
40
|
+
],
|
|
41
|
+
"author": "el_jijuna",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/el_jijuna/vite-legacy-pass-through.git"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/el_jijuna/vite-legacy-pass-through/issues"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/el_jijuna/vite-legacy-pass-through#readme",
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"vite": "^8.0.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"tsup": "^8.4.0",
|
|
59
|
+
"typescript": "^5.8.3",
|
|
60
|
+
"vite": "^8.0.3",
|
|
61
|
+
"vitest": "^4.1.2"
|
|
62
|
+
}
|
|
63
|
+
}
|