@tanstack/router-vite-plugin 1.24.1 → 1.26.6
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/dist/cjs/compilers.cjs +335 -0
- package/dist/cjs/compilers.cjs.map +1 -0
- package/dist/cjs/compilers.d.cts +38 -0
- package/dist/cjs/constants.cjs +5 -0
- package/dist/cjs/constants.cjs.map +1 -0
- package/dist/cjs/constants.d.cts +1 -0
- package/dist/cjs/eliminateUnreferencedIdentifiers.cjs +144 -0
- package/dist/cjs/eliminateUnreferencedIdentifiers.cjs.map +1 -0
- package/dist/cjs/eliminateUnreferencedIdentifiers.d.cts +8 -0
- package/dist/cjs/index.cjs +103 -8
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +55 -2
- package/dist/esm/compilers.d.ts +38 -0
- package/dist/esm/compilers.js +316 -0
- package/dist/esm/compilers.js.map +1 -0
- package/dist/esm/constants.d.ts +1 -0
- package/dist/esm/constants.js +5 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/eliminateUnreferencedIdentifiers.d.ts +8 -0
- package/dist/esm/eliminateUnreferencedIdentifiers.js +127 -0
- package/dist/esm/eliminateUnreferencedIdentifiers.js.map +1 -0
- package/dist/esm/index.d.ts +55 -2
- package/dist/esm/index.js +103 -8
- package/dist/esm/index.js.map +1 -1
- package/package.json +18 -1
- package/src/compilers.ts +420 -0
- package/src/constants.ts +1 -0
- package/src/eliminateUnreferencedIdentifiers.ts +287 -0
- package/src/index.ts +167 -8
- package/src/tests/index.test.ts +60 -0
- package/src/tests/shared/imported.tsx +11 -0
- package/src/tests/snapshots/function-declaration.tsx +10 -0
- package/src/tests/snapshots/function-declaration?split.tsx +29 -0
- package/src/tests/snapshots/imported.tsx +10 -0
- package/src/tests/snapshots/imported?split.tsx +5 -0
- package/src/tests/snapshots/inline.tsx +8 -0
- package/src/tests/snapshots/inline?split.tsx +18 -0
- package/src/tests/snapshots/random-number.tsx +11 -0
- package/src/tests/snapshots/random-number?split.tsx +27 -0
- package/src/tests/test-files/function-declaration.tsx +39 -0
- package/src/tests/test-files/imported.tsx +8 -0
- package/src/tests/test-files/inline.tsx +25 -0
- package/src/tests/test-files/random-number.tsx +83 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const t = require("@babel/types");
|
|
4
|
+
const template = require("@babel/template");
|
|
5
|
+
const babel = require("@babel/core");
|
|
6
|
+
const constants = require("./constants.cjs");
|
|
7
|
+
const eliminateUnreferencedIdentifiers = require("./eliminateUnreferencedIdentifiers.cjs");
|
|
8
|
+
function _interopNamespaceDefault(e) {
|
|
9
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
10
|
+
if (e) {
|
|
11
|
+
for (const k in e) {
|
|
12
|
+
if (k !== "default") {
|
|
13
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: () => e[k]
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
n.default = e;
|
|
22
|
+
return Object.freeze(n);
|
|
23
|
+
}
|
|
24
|
+
const t__namespace = /* @__PURE__ */ _interopNamespaceDefault(t);
|
|
25
|
+
const template__namespace = /* @__PURE__ */ _interopNamespaceDefault(template);
|
|
26
|
+
const babel__namespace = /* @__PURE__ */ _interopNamespaceDefault(babel);
|
|
27
|
+
function makeCompile(makeOpts) {
|
|
28
|
+
return async (opts) => {
|
|
29
|
+
const res = await babel__namespace.transform(opts.code, {
|
|
30
|
+
plugins: [
|
|
31
|
+
["@babel/plugin-syntax-jsx", {}],
|
|
32
|
+
[
|
|
33
|
+
"@babel/plugin-syntax-typescript",
|
|
34
|
+
{
|
|
35
|
+
isTSX: true
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
...opts.getBabelConfig().plugins
|
|
39
|
+
],
|
|
40
|
+
root: makeOpts.root,
|
|
41
|
+
filename: opts.filename,
|
|
42
|
+
sourceMaps: true
|
|
43
|
+
});
|
|
44
|
+
if (res == null ? void 0 : res.code) {
|
|
45
|
+
return {
|
|
46
|
+
code: res.code,
|
|
47
|
+
map: res.map
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
code: opts.code,
|
|
52
|
+
map: null
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function compileFile(opts) {
|
|
57
|
+
return await opts.compile({
|
|
58
|
+
code: opts.code,
|
|
59
|
+
filename: opts.filename,
|
|
60
|
+
getBabelConfig: () => ({
|
|
61
|
+
plugins: [
|
|
62
|
+
[
|
|
63
|
+
{
|
|
64
|
+
visitor: {
|
|
65
|
+
Program: {
|
|
66
|
+
enter(programPath, state) {
|
|
67
|
+
const splitUrl = `${constants.splitPrefix}:${state.filename}?${constants.splitPrefix}`;
|
|
68
|
+
programPath.traverse(
|
|
69
|
+
{
|
|
70
|
+
CallExpression: (path) => {
|
|
71
|
+
if (path.node.callee.type === "Identifier") {
|
|
72
|
+
if (path.node.callee.name === "createRoute" || path.node.callee.name === "createFileRoute") {
|
|
73
|
+
if (path.parentPath.node.type === "CallExpression") {
|
|
74
|
+
const options = resolveIdentifier(
|
|
75
|
+
path,
|
|
76
|
+
path.parentPath.node.arguments[0]
|
|
77
|
+
);
|
|
78
|
+
let found = false;
|
|
79
|
+
if (t__namespace.isObjectExpression(options)) {
|
|
80
|
+
options.properties.forEach((prop) => {
|
|
81
|
+
if (t__namespace.isObjectProperty(prop)) {
|
|
82
|
+
if (t__namespace.isIdentifier(prop.key)) {
|
|
83
|
+
if (prop.key.name === "component") {
|
|
84
|
+
const value = prop.value;
|
|
85
|
+
if (t__namespace.isIdentifier(value)) {
|
|
86
|
+
removeIdentifierLiteral(path, value);
|
|
87
|
+
}
|
|
88
|
+
programPath.unshiftContainer("body", [
|
|
89
|
+
template__namespace.smart(
|
|
90
|
+
`import { lazyRouteComponent } from '@tanstack/react-router'`
|
|
91
|
+
)(),
|
|
92
|
+
template__namespace.smart(
|
|
93
|
+
`const $$splitComponentImporter = () => import('${splitUrl}')`
|
|
94
|
+
)()
|
|
95
|
+
]);
|
|
96
|
+
prop.value = template__namespace.expression(
|
|
97
|
+
`lazyRouteComponent($$splitComponentImporter, 'component')`
|
|
98
|
+
)();
|
|
99
|
+
programPath.pushContainer("body", [
|
|
100
|
+
template__namespace.smart(
|
|
101
|
+
`function DummyComponent() { return null }`
|
|
102
|
+
)()
|
|
103
|
+
]);
|
|
104
|
+
found = true;
|
|
105
|
+
} else if (prop.key.name === "loader") {
|
|
106
|
+
const value = prop.value;
|
|
107
|
+
if (t__namespace.isIdentifier(value)) {
|
|
108
|
+
removeIdentifierLiteral(path, value);
|
|
109
|
+
}
|
|
110
|
+
programPath.unshiftContainer("body", [
|
|
111
|
+
template__namespace.smart(
|
|
112
|
+
`import { lazyFn } from '@tanstack/react-router'`
|
|
113
|
+
)(),
|
|
114
|
+
template__namespace.smart(
|
|
115
|
+
`const $$splitLoaderImporter = () => import('${splitUrl}')`
|
|
116
|
+
)()
|
|
117
|
+
]);
|
|
118
|
+
prop.value = template__namespace.expression(
|
|
119
|
+
`lazyFn($$splitLoaderImporter, 'loader')`
|
|
120
|
+
)();
|
|
121
|
+
found = true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (found) {
|
|
128
|
+
programPath.pushContainer("body", [
|
|
129
|
+
template__namespace.smart(
|
|
130
|
+
`function TSR_Dummy_Component() {}`
|
|
131
|
+
)()
|
|
132
|
+
]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
state
|
|
140
|
+
);
|
|
141
|
+
eliminateUnreferencedIdentifiers.eliminateUnreferencedIdentifiers(programPath);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
root: process.cwd(),
|
|
148
|
+
minify: process.env.NODE_ENV === "production"
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
].filter(Boolean)
|
|
152
|
+
})
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function resolveIdentifier(path, node) {
|
|
156
|
+
if (t__namespace.isIdentifier(node)) {
|
|
157
|
+
const binding = path.scope.getBinding(node.name);
|
|
158
|
+
if (binding) {
|
|
159
|
+
const declarator = binding.path.node;
|
|
160
|
+
if (t__namespace.isObjectExpression(declarator.init)) {
|
|
161
|
+
return declarator.init;
|
|
162
|
+
} else if (t__namespace.isFunctionDeclaration(declarator.init)) {
|
|
163
|
+
return declarator.init;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return void 0;
|
|
167
|
+
}
|
|
168
|
+
return node;
|
|
169
|
+
}
|
|
170
|
+
function removeIdentifierLiteral(path, node) {
|
|
171
|
+
if (t__namespace.isIdentifier(node)) {
|
|
172
|
+
const binding = path.scope.getBinding(node.name);
|
|
173
|
+
if (binding) {
|
|
174
|
+
binding.path.remove();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const splitNodeTypes = ["component", "loader"];
|
|
179
|
+
async function splitFile(opts) {
|
|
180
|
+
return await opts.compile({
|
|
181
|
+
code: opts.code,
|
|
182
|
+
filename: opts.filename,
|
|
183
|
+
getBabelConfig: () => ({
|
|
184
|
+
plugins: [
|
|
185
|
+
[
|
|
186
|
+
{
|
|
187
|
+
visitor: {
|
|
188
|
+
Program: {
|
|
189
|
+
enter(programPath, state) {
|
|
190
|
+
const splitNodesByType = {
|
|
191
|
+
component: void 0,
|
|
192
|
+
loader: void 0
|
|
193
|
+
};
|
|
194
|
+
programPath.traverse(
|
|
195
|
+
{
|
|
196
|
+
CallExpression: (path) => {
|
|
197
|
+
if (path.node.callee.type === "Identifier") {
|
|
198
|
+
if (path.node.callee.name === "createFileRoute") {
|
|
199
|
+
if (path.parentPath.node.type === "CallExpression") {
|
|
200
|
+
const options = resolveIdentifier(
|
|
201
|
+
path,
|
|
202
|
+
path.parentPath.node.arguments[0]
|
|
203
|
+
);
|
|
204
|
+
if (t__namespace.isObjectExpression(options)) {
|
|
205
|
+
options.properties.forEach((prop) => {
|
|
206
|
+
if (t__namespace.isObjectProperty(prop)) {
|
|
207
|
+
splitNodeTypes.forEach((type) => {
|
|
208
|
+
if (t__namespace.isIdentifier(prop.key)) {
|
|
209
|
+
if (prop.key.name === type) {
|
|
210
|
+
splitNodesByType[type] = prop.value;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
options.properties = [];
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
state
|
|
224
|
+
);
|
|
225
|
+
splitNodeTypes.forEach((splitType) => {
|
|
226
|
+
let splitNode = splitNodesByType[splitType];
|
|
227
|
+
if (!splitNode) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
while (t__namespace.isIdentifier(splitNode)) {
|
|
231
|
+
const binding = programPath.scope.getBinding(
|
|
232
|
+
splitNode.name
|
|
233
|
+
);
|
|
234
|
+
splitNode = binding == null ? void 0 : binding.path.node;
|
|
235
|
+
}
|
|
236
|
+
if (splitNode) {
|
|
237
|
+
if (t__namespace.isFunctionDeclaration(splitNode)) {
|
|
238
|
+
programPath.pushContainer(
|
|
239
|
+
"body",
|
|
240
|
+
t__namespace.variableDeclaration("const", [
|
|
241
|
+
t__namespace.variableDeclarator(
|
|
242
|
+
t__namespace.identifier(splitType),
|
|
243
|
+
t__namespace.functionExpression(
|
|
244
|
+
splitNode.id || null,
|
|
245
|
+
// Anonymize the function expression
|
|
246
|
+
splitNode.params,
|
|
247
|
+
splitNode.body,
|
|
248
|
+
splitNode.generator,
|
|
249
|
+
splitNode.async
|
|
250
|
+
)
|
|
251
|
+
)
|
|
252
|
+
])
|
|
253
|
+
);
|
|
254
|
+
} else if (t__namespace.isFunctionExpression(splitNode) || t__namespace.isArrowFunctionExpression(splitNode)) {
|
|
255
|
+
programPath.pushContainer(
|
|
256
|
+
"body",
|
|
257
|
+
t__namespace.variableDeclaration("const", [
|
|
258
|
+
t__namespace.variableDeclarator(
|
|
259
|
+
t__namespace.identifier(splitType),
|
|
260
|
+
splitNode
|
|
261
|
+
)
|
|
262
|
+
])
|
|
263
|
+
);
|
|
264
|
+
} else if (t__namespace.isImportSpecifier(splitNode)) {
|
|
265
|
+
programPath.pushContainer(
|
|
266
|
+
"body",
|
|
267
|
+
t__namespace.variableDeclaration("const", [
|
|
268
|
+
t__namespace.variableDeclarator(
|
|
269
|
+
t__namespace.identifier(splitType),
|
|
270
|
+
splitNode.local
|
|
271
|
+
)
|
|
272
|
+
])
|
|
273
|
+
);
|
|
274
|
+
} else {
|
|
275
|
+
console.log(splitNode);
|
|
276
|
+
throw new Error(
|
|
277
|
+
`Unexpected splitNode type: ${splitNode.type}`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
programPath.node.body = programPath.node.body.filter(
|
|
282
|
+
(node) => {
|
|
283
|
+
return node !== splitNode;
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
programPath.pushContainer("body", [
|
|
287
|
+
t__namespace.exportNamedDeclaration(null, [
|
|
288
|
+
t__namespace.exportSpecifier(
|
|
289
|
+
t__namespace.identifier(splitType),
|
|
290
|
+
t__namespace.identifier(splitType)
|
|
291
|
+
)
|
|
292
|
+
])
|
|
293
|
+
]);
|
|
294
|
+
});
|
|
295
|
+
programPath.traverse({
|
|
296
|
+
ExportNamedDeclaration(path) {
|
|
297
|
+
if (path.node.declaration) {
|
|
298
|
+
if (t__namespace.isVariableDeclaration(path.node.declaration)) {
|
|
299
|
+
path.replaceWith(
|
|
300
|
+
t__namespace.importDeclaration(
|
|
301
|
+
path.node.declaration.declarations.map(
|
|
302
|
+
(decl) => t__namespace.importSpecifier(
|
|
303
|
+
t__namespace.identifier(decl.id.name),
|
|
304
|
+
t__namespace.identifier(decl.id.name)
|
|
305
|
+
)
|
|
306
|
+
),
|
|
307
|
+
t__namespace.stringLiteral(
|
|
308
|
+
opts.filename.split(
|
|
309
|
+
`?${constants.splitPrefix}`
|
|
310
|
+
)[0]
|
|
311
|
+
)
|
|
312
|
+
)
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
eliminateUnreferencedIdentifiers.eliminateUnreferencedIdentifiers(programPath);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
root: process.cwd(),
|
|
325
|
+
minify: process.env.NODE_ENV === "production"
|
|
326
|
+
}
|
|
327
|
+
]
|
|
328
|
+
].filter(Boolean)
|
|
329
|
+
})
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
exports.compileFile = compileFile;
|
|
333
|
+
exports.makeCompile = makeCompile;
|
|
334
|
+
exports.splitFile = splitFile;
|
|
335
|
+
//# sourceMappingURL=compilers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compilers.cjs","sources":["../../src/compilers.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport * as template from '@babel/template'\nimport * as babel from '@babel/core'\nimport { splitPrefix } from './constants'\nimport { eliminateUnreferencedIdentifiers } from './eliminateUnreferencedIdentifiers'\n\ntype SplitModulesById = Record<\n string,\n { id: string; node: t.FunctionExpression }\n>\n\ninterface State {\n filename: string\n opts: {\n minify: boolean\n root: string\n }\n imported: Record<string, boolean>\n refs: Set<any>\n serverIndex: number\n splitIndex: number\n splitModulesById: SplitModulesById\n}\n\nexport type CompileFn = (compileOpts: {\n code: string\n filename: string\n getBabelConfig: () => { plugins: Array<any> }\n}) => Promise<{\n code: string\n map: any\n}>\n\nexport function makeCompile(makeOpts: { root: string }) {\n return async (opts: {\n code: string\n filename: string\n getBabelConfig: () => { plugins: Array<any> }\n }): Promise<{\n code: string\n map: any\n }> => {\n const res = await babel.transform(opts.code, {\n plugins: [\n ['@babel/plugin-syntax-jsx', {}],\n [\n '@babel/plugin-syntax-typescript',\n {\n isTSX: true,\n },\n ],\n ...opts.getBabelConfig().plugins,\n ],\n root: makeOpts.root,\n filename: opts.filename,\n sourceMaps: true,\n })\n\n if (res?.code) {\n return {\n code: res.code,\n map: res.map,\n }\n }\n\n return {\n code: opts.code,\n map: null,\n }\n }\n}\n\nexport async function compileFile(opts: {\n code: string\n compile: CompileFn\n filename: string\n}) {\n return await opts.compile({\n code: opts.code,\n filename: opts.filename,\n getBabelConfig: () => ({\n plugins: [\n [\n {\n visitor: {\n Program: {\n enter(programPath: babel.NodePath<t.Program>, state: State) {\n const splitUrl = `${splitPrefix}:${state.filename}?${splitPrefix}`\n\n programPath.traverse(\n {\n CallExpression: (path) => {\n if (path.node.callee.type === 'Identifier') {\n if (\n path.node.callee.name === 'createRoute' ||\n path.node.callee.name === 'createFileRoute'\n ) {\n if (\n path.parentPath.node.type === 'CallExpression'\n ) {\n const options = resolveIdentifier(\n path,\n path.parentPath.node.arguments[0],\n )\n\n let found = false\n\n if (t.isObjectExpression(options)) {\n options.properties.forEach((prop) => {\n if (t.isObjectProperty(prop)) {\n if (t.isIdentifier(prop.key)) {\n if (prop.key.name === 'component') {\n const value = prop.value\n\n if (t.isIdentifier(value)) {\n removeIdentifierLiteral(path, value)\n }\n\n // Prepend the import statement to the program along with the importer function\n\n programPath.unshiftContainer('body', [\n template.smart(\n `import { lazyRouteComponent } from '@tanstack/react-router'`,\n )() as t.Statement,\n template.smart(\n `const $$splitComponentImporter = () => import('${splitUrl}')`,\n )() as t.Statement,\n ])\n\n prop.value = template.expression(\n `lazyRouteComponent($$splitComponentImporter, 'component')`,\n )() as any\n\n programPath.pushContainer('body', [\n template.smart(\n `function DummyComponent() { return null }`,\n )() as t.Statement,\n ])\n\n found = true\n } else if (prop.key.name === 'loader') {\n const value = prop.value\n\n if (t.isIdentifier(value)) {\n removeIdentifierLiteral(path, value)\n }\n\n // Prepend the import statement to the program along with the importer function\n\n programPath.unshiftContainer('body', [\n template.smart(\n `import { lazyFn } from '@tanstack/react-router'`,\n )() as t.Statement,\n template.smart(\n `const $$splitLoaderImporter = () => import('${splitUrl}')`,\n )() as t.Statement,\n ])\n\n prop.value = template.expression(\n `lazyFn($$splitLoaderImporter, 'loader')`,\n )() as any\n\n found = true\n }\n }\n }\n })\n }\n\n if (found as boolean) {\n programPath.pushContainer('body', [\n template.smart(\n `function TSR_Dummy_Component() {}`,\n )() as t.Statement,\n ])\n }\n }\n }\n }\n },\n },\n state,\n )\n\n eliminateUnreferencedIdentifiers(programPath)\n },\n },\n },\n },\n {\n root: process.cwd(),\n minify: process.env.NODE_ENV === 'production',\n },\n ],\n ].filter(Boolean),\n }),\n })\n}\n\n// Reusable function to get literal value or resolve variable to literal\nfunction resolveIdentifier(path: any, node: any) {\n if (t.isIdentifier(node)) {\n const binding = path.scope.getBinding(node.name)\n if (\n binding\n // && binding.kind === 'const'\n ) {\n const declarator = binding.path.node\n if (t.isObjectExpression(declarator.init)) {\n return declarator.init\n } else if (t.isFunctionDeclaration(declarator.init)) {\n return declarator.init\n }\n }\n return undefined\n }\n\n return node\n}\n\nfunction removeIdentifierLiteral(path: any, node: any) {\n if (t.isIdentifier(node)) {\n const binding = path.scope.getBinding(node.name)\n if (binding) {\n binding.path.remove()\n }\n }\n}\n\nconst splitNodeTypes = ['component', 'loader'] as const\ntype SplitNodeType = (typeof splitNodeTypes)[number]\n\nexport async function splitFile(opts: {\n code: string\n compile: CompileFn\n filename: string\n // ref: string\n}) {\n return await opts.compile({\n code: opts.code,\n filename: opts.filename,\n getBabelConfig: () => ({\n plugins: [\n [\n {\n visitor: {\n Program: {\n enter(programPath: babel.NodePath<t.Program>, state: State) {\n const splitNodesByType: Record<\n SplitNodeType,\n t.Node | undefined\n > = {\n component: undefined,\n loader: undefined,\n }\n\n // Find the node\n programPath.traverse(\n {\n CallExpression: (path) => {\n if (path.node.callee.type === 'Identifier') {\n if (path.node.callee.name === 'createFileRoute') {\n if (\n path.parentPath.node.type === 'CallExpression'\n ) {\n const options = resolveIdentifier(\n path,\n path.parentPath.node.arguments[0],\n )\n\n if (t.isObjectExpression(options)) {\n options.properties.forEach((prop) => {\n if (t.isObjectProperty(prop)) {\n splitNodeTypes.forEach((type) => {\n if (t.isIdentifier(prop.key)) {\n if (prop.key.name === type) {\n splitNodesByType[type] = prop.value\n }\n }\n })\n }\n })\n\n // Remove all of the options\n options.properties = []\n }\n }\n }\n }\n },\n },\n state,\n )\n\n splitNodeTypes.forEach((splitType) => {\n let splitNode = splitNodesByType[splitType]\n\n if (!splitNode) {\n return\n }\n\n while (t.isIdentifier(splitNode)) {\n const binding = programPath.scope.getBinding(\n splitNode.name,\n )\n splitNode = binding?.path.node\n }\n\n // Add the node to the program\n if (splitNode) {\n if (t.isFunctionDeclaration(splitNode)) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n t.functionExpression(\n splitNode.id || null, // Anonymize the function expression\n splitNode.params,\n splitNode.body,\n splitNode.generator,\n splitNode.async,\n ),\n ),\n ]),\n )\n } else if (\n t.isFunctionExpression(splitNode) ||\n t.isArrowFunctionExpression(splitNode)\n ) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n splitNode as any,\n ),\n ]),\n )\n } else if (t.isImportSpecifier(splitNode)) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n splitNode.local,\n ),\n ]),\n )\n } else {\n console.log(splitNode)\n throw new Error(\n `Unexpected splitNode type: ${splitNode.type}`,\n )\n }\n }\n\n // If the splitNode exists at the top of the program\n // then we need to remove that copy\n programPath.node.body = programPath.node.body.filter(\n (node) => {\n // console.log(node)\n return node !== splitNode\n },\n )\n\n // Export the node\n programPath.pushContainer('body', [\n t.exportNamedDeclaration(null, [\n t.exportSpecifier(\n t.identifier(splitType),\n t.identifier(splitType),\n ),\n ]),\n ])\n })\n\n // convert exports to imports from the original file\n programPath.traverse({\n ExportNamedDeclaration(path) {\n // e.g. export const x = 1 or export { x }\n // becomes\n // import { x } from '${opts.id}'\n\n if (path.node.declaration) {\n if (t.isVariableDeclaration(path.node.declaration)) {\n path.replaceWith(\n t.importDeclaration(\n path.node.declaration.declarations.map((decl) =>\n t.importSpecifier(\n t.identifier((decl.id as any).name),\n t.identifier((decl.id as any).name),\n ),\n ),\n t.stringLiteral(\n opts.filename.split(\n `?${splitPrefix}`,\n )[0] as string,\n ),\n ),\n )\n }\n }\n },\n })\n\n eliminateUnreferencedIdentifiers(programPath)\n },\n },\n },\n },\n {\n root: process.cwd(),\n minify: process.env.NODE_ENV === 'production',\n },\n ],\n ].filter(Boolean),\n }),\n })\n}\n"],"names":["babel","splitPrefix","t","template","eliminateUnreferencedIdentifiers"],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type CompileFn = (compileOpts: {
|
|
2
|
+
code: string;
|
|
3
|
+
filename: string;
|
|
4
|
+
getBabelConfig: () => {
|
|
5
|
+
plugins: Array<any>;
|
|
6
|
+
};
|
|
7
|
+
}) => Promise<{
|
|
8
|
+
code: string;
|
|
9
|
+
map: any;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function makeCompile(makeOpts: {
|
|
12
|
+
root: string;
|
|
13
|
+
}): (opts: {
|
|
14
|
+
code: string;
|
|
15
|
+
filename: string;
|
|
16
|
+
getBabelConfig: () => {
|
|
17
|
+
plugins: Array<any>;
|
|
18
|
+
};
|
|
19
|
+
}) => Promise<{
|
|
20
|
+
code: string;
|
|
21
|
+
map: any;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function compileFile(opts: {
|
|
24
|
+
code: string;
|
|
25
|
+
compile: CompileFn;
|
|
26
|
+
filename: string;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
code: string;
|
|
29
|
+
map: any;
|
|
30
|
+
}>;
|
|
31
|
+
export declare function splitFile(opts: {
|
|
32
|
+
code: string;
|
|
33
|
+
compile: CompileFn;
|
|
34
|
+
filename: string;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
code: string;
|
|
37
|
+
map: any;
|
|
38
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.cjs","sources":["../../src/constants.ts"],"sourcesContent":["export const splitPrefix = 'tsr-split'\n"],"names":[],"mappings":";;AAAO,MAAM,cAAc;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const splitPrefix = "tsr-split";
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const t = require("@babel/types");
|
|
4
|
+
function _interopNamespaceDefault(e) {
|
|
5
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
6
|
+
if (e) {
|
|
7
|
+
for (const k in e) {
|
|
8
|
+
if (k !== "default") {
|
|
9
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
10
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: () => e[k]
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
n.default = e;
|
|
18
|
+
return Object.freeze(n);
|
|
19
|
+
}
|
|
20
|
+
const t__namespace = /* @__PURE__ */ _interopNamespaceDefault(t);
|
|
21
|
+
const eliminateUnreferencedIdentifiers = (programPath, refs) => {
|
|
22
|
+
let referencesRemovedInThisPass;
|
|
23
|
+
const shouldBeRemoved = (ident) => {
|
|
24
|
+
if (isIdentifierReferenced(ident))
|
|
25
|
+
return false;
|
|
26
|
+
if (!refs)
|
|
27
|
+
return true;
|
|
28
|
+
return refs.has(ident);
|
|
29
|
+
};
|
|
30
|
+
const sweepFunction = (path) => {
|
|
31
|
+
const identifier = getIdentifier(path);
|
|
32
|
+
if ((identifier == null ? void 0 : identifier.node) && shouldBeRemoved(identifier)) {
|
|
33
|
+
++referencesRemovedInThisPass;
|
|
34
|
+
if (t__namespace.isAssignmentExpression(path.parentPath.node) || t__namespace.isVariableDeclarator(path.parentPath.node)) {
|
|
35
|
+
path.parentPath.remove();
|
|
36
|
+
} else {
|
|
37
|
+
path.remove();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const sweepImport = (path) => {
|
|
42
|
+
const local = path.get("local");
|
|
43
|
+
if (shouldBeRemoved(local)) {
|
|
44
|
+
++referencesRemovedInThisPass;
|
|
45
|
+
path.remove();
|
|
46
|
+
if (path.parent.specifiers.length === 0) {
|
|
47
|
+
path.parentPath.remove();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
do {
|
|
52
|
+
referencesRemovedInThisPass = 0;
|
|
53
|
+
programPath.scope.crawl();
|
|
54
|
+
programPath.traverse({
|
|
55
|
+
VariableDeclarator(path) {
|
|
56
|
+
if (path.node.id.type === "Identifier") {
|
|
57
|
+
const local = path.get("id");
|
|
58
|
+
if (shouldBeRemoved(local)) {
|
|
59
|
+
++referencesRemovedInThisPass;
|
|
60
|
+
path.remove();
|
|
61
|
+
}
|
|
62
|
+
} else if (path.node.id.type === "ObjectPattern") {
|
|
63
|
+
const pattern = path.get("id");
|
|
64
|
+
const beforeCount = referencesRemovedInThisPass;
|
|
65
|
+
const properties = pattern.get("properties");
|
|
66
|
+
properties.forEach((property) => {
|
|
67
|
+
const local = property.get(
|
|
68
|
+
property.node.type === "ObjectProperty" ? "value" : (
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
70
|
+
property.node.type === "RestElement" ? "argument" : function() {
|
|
71
|
+
throw new Error("invariant");
|
|
72
|
+
}()
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
if (shouldBeRemoved(local)) {
|
|
76
|
+
++referencesRemovedInThisPass;
|
|
77
|
+
property.remove();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
if (beforeCount !== referencesRemovedInThisPass && pattern.get("properties").length < 1) {
|
|
81
|
+
path.remove();
|
|
82
|
+
}
|
|
83
|
+
} else if (path.node.id.type === "ArrayPattern") {
|
|
84
|
+
const pattern = path.get("id");
|
|
85
|
+
const beforeCount = referencesRemovedInThisPass;
|
|
86
|
+
const elements = pattern.get("elements");
|
|
87
|
+
elements.forEach((e) => {
|
|
88
|
+
var _a, _b;
|
|
89
|
+
let local;
|
|
90
|
+
if (((_a = e.node) == null ? void 0 : _a.type) === "Identifier") {
|
|
91
|
+
local = e;
|
|
92
|
+
} else if (((_b = e.node) == null ? void 0 : _b.type) === "RestElement") {
|
|
93
|
+
local = e.get("argument");
|
|
94
|
+
} else {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (shouldBeRemoved(local)) {
|
|
98
|
+
++referencesRemovedInThisPass;
|
|
99
|
+
e.remove();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
if (beforeCount !== referencesRemovedInThisPass && pattern.get("elements").length < 1) {
|
|
103
|
+
path.remove();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
FunctionDeclaration: sweepFunction,
|
|
108
|
+
FunctionExpression: sweepFunction,
|
|
109
|
+
ArrowFunctionExpression: sweepFunction,
|
|
110
|
+
ImportSpecifier: sweepImport,
|
|
111
|
+
ImportDefaultSpecifier: sweepImport,
|
|
112
|
+
ImportNamespaceSpecifier: sweepImport
|
|
113
|
+
});
|
|
114
|
+
} while (referencesRemovedInThisPass);
|
|
115
|
+
};
|
|
116
|
+
function getIdentifier(path) {
|
|
117
|
+
const parentPath = path.parentPath;
|
|
118
|
+
if (parentPath.type === "VariableDeclarator") {
|
|
119
|
+
const variablePath = parentPath;
|
|
120
|
+
const name = variablePath.get("id");
|
|
121
|
+
return name.node.type === "Identifier" ? name : null;
|
|
122
|
+
}
|
|
123
|
+
if (parentPath.type === "AssignmentExpression") {
|
|
124
|
+
const variablePath = parentPath;
|
|
125
|
+
const name = variablePath.get("left");
|
|
126
|
+
return name.node.type === "Identifier" ? name : null;
|
|
127
|
+
}
|
|
128
|
+
if (path.node.type === "ArrowFunctionExpression") {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
return path.node.id && path.node.id.type === "Identifier" ? path.get("id") : null;
|
|
132
|
+
}
|
|
133
|
+
function isIdentifierReferenced(ident) {
|
|
134
|
+
const binding = ident.scope.getBinding(ident.node.name);
|
|
135
|
+
if (binding == null ? void 0 : binding.referenced) {
|
|
136
|
+
if (binding.path.type === "FunctionDeclaration") {
|
|
137
|
+
return !binding.constantViolations.concat(binding.referencePaths).every((ref) => ref.findParent((parent) => parent === binding.path));
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
exports.eliminateUnreferencedIdentifiers = eliminateUnreferencedIdentifiers;
|
|
144
|
+
//# sourceMappingURL=eliminateUnreferencedIdentifiers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eliminateUnreferencedIdentifiers.cjs","sources":["../../src/eliminateUnreferencedIdentifiers.ts"],"sourcesContent":["// Copied from https://github.com/pcattori/vite-env-only/blob/main/src/dce.ts\n// Adapted with some minor changes for the purpose of this project\n\nimport * as t from '@babel/types'\nimport type { types as BabelTypes } from '@babel/core'\nimport type { NodePath } from '@babel/traverse'\n\ntype IdentifierPath = NodePath<BabelTypes.Identifier>\n\n// export function findReferencedIdentifiers(\n// programPath: NodePath<BabelTypes.Program>,\n// ): Set<IdentifierPath> {\n// const refs = new Set<IdentifierPath>()\n\n// function markFunction(\n// path: NodePath<\n// | BabelTypes.FunctionDeclaration\n// | BabelTypes.FunctionExpression\n// | BabelTypes.ArrowFunctionExpression\n// >,\n// ) {\n// const ident = getIdentifier(path)\n// if (ident?.node && isIdentifierReferenced(ident)) {\n// refs.add(ident)\n// }\n// }\n\n// function markImport(\n// path: NodePath<\n// | BabelTypes.ImportSpecifier\n// | BabelTypes.ImportDefaultSpecifier\n// | BabelTypes.ImportNamespaceSpecifier\n// >,\n// ) {\n// const local = path.get('local')\n// if (isIdentifierReferenced(local)) {\n// refs.add(local)\n// }\n// }\n\n// programPath.traverse({\n// VariableDeclarator(path) {\n// if (path.node.id.type === 'Identifier') {\n// const local = path.get('id') as NodePath<BabelTypes.Identifier>\n// if (isIdentifierReferenced(local)) {\n// refs.add(local)\n// }\n// } else if (path.node.id.type === 'ObjectPattern') {\n// const pattern = path.get('id') as NodePath<BabelTypes.ObjectPattern>\n\n// const properties = pattern.get('properties')\n// properties.forEach((p) => {\n// const local = p.get(\n// p.node.type === 'ObjectProperty'\n// ? 'value'\n// : p.node.type === 'RestElement'\n// ? 'argument'\n// : (function () {\n// throw new Error('invariant')\n// })(),\n// ) as NodePath<BabelTypes.Identifier>\n// if (isIdentifierReferenced(local)) {\n// refs.add(local)\n// }\n// })\n// } else if (path.node.id.type === 'ArrayPattern') {\n// const pattern = path.get('id') as NodePath<BabelTypes.ArrayPattern>\n\n// const elements = pattern.get('elements')\n// elements.forEach((e) => {\n// let local: NodePath<BabelTypes.Identifier>\n// if (e.node?.type === 'Identifier') {\n// local = e as NodePath<BabelTypes.Identifier>\n// } else if (e.node?.type === 'RestElement') {\n// local = e.get('argument') as NodePath<BabelTypes.Identifier>\n// } else {\n// return\n// }\n\n// if (isIdentifierReferenced(local)) {\n// refs.add(local)\n// }\n// })\n// }\n// },\n\n// FunctionDeclaration: markFunction,\n// FunctionExpression: markFunction,\n// ArrowFunctionExpression: markFunction,\n// ImportSpecifier: markImport,\n// ImportDefaultSpecifier: markImport,\n// ImportNamespaceSpecifier: markImport,\n// })\n// return refs\n// }\n\n/**\n * @param refs - If provided, only these identifiers will be considered for removal.\n */\nexport const eliminateUnreferencedIdentifiers = (\n programPath: NodePath<BabelTypes.Program>,\n refs?: Set<IdentifierPath>,\n) => {\n let referencesRemovedInThisPass: number\n\n const shouldBeRemoved = (ident: IdentifierPath) => {\n if (isIdentifierReferenced(ident)) return false\n if (!refs) return true\n return refs.has(ident)\n }\n\n const sweepFunction = (\n path: NodePath<\n | BabelTypes.FunctionDeclaration\n | BabelTypes.FunctionExpression\n | BabelTypes.ArrowFunctionExpression\n >,\n ) => {\n const identifier = getIdentifier(path)\n if (identifier?.node && shouldBeRemoved(identifier)) {\n ++referencesRemovedInThisPass\n\n if (\n t.isAssignmentExpression(path.parentPath.node) ||\n t.isVariableDeclarator(path.parentPath.node)\n ) {\n path.parentPath.remove()\n } else {\n path.remove()\n }\n }\n }\n\n const sweepImport = (\n path: NodePath<\n | BabelTypes.ImportSpecifier\n | BabelTypes.ImportDefaultSpecifier\n | BabelTypes.ImportNamespaceSpecifier\n >,\n ) => {\n const local = path.get('local')\n if (shouldBeRemoved(local)) {\n ++referencesRemovedInThisPass\n path.remove()\n if (\n (path.parent as BabelTypes.ImportDeclaration).specifiers.length === 0\n ) {\n path.parentPath.remove()\n }\n }\n }\n\n // Traverse again to remove unused references. This happens at least once,\n // then repeats until no more references are removed.\n do {\n referencesRemovedInThisPass = 0\n\n programPath.scope.crawl()\n\n programPath.traverse({\n VariableDeclarator(path) {\n if (path.node.id.type === 'Identifier') {\n const local = path.get('id') as NodePath<BabelTypes.Identifier>\n if (shouldBeRemoved(local)) {\n ++referencesRemovedInThisPass\n path.remove()\n }\n } else if (path.node.id.type === 'ObjectPattern') {\n const pattern = path.get('id') as NodePath<BabelTypes.ObjectPattern>\n\n const beforeCount = referencesRemovedInThisPass\n const properties = pattern.get('properties')\n properties.forEach((property) => {\n const local = property.get(\n property.node.type === 'ObjectProperty'\n ? 'value'\n : // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n property.node.type === 'RestElement'\n ? 'argument'\n : (function () {\n throw new Error('invariant')\n })(),\n ) as NodePath<BabelTypes.Identifier>\n\n if (shouldBeRemoved(local)) {\n ++referencesRemovedInThisPass\n property.remove()\n }\n })\n\n if (\n beforeCount !== referencesRemovedInThisPass &&\n pattern.get('properties').length < 1\n ) {\n path.remove()\n }\n } else if (path.node.id.type === 'ArrayPattern') {\n const pattern = path.get('id') as NodePath<BabelTypes.ArrayPattern>\n\n const beforeCount = referencesRemovedInThisPass\n const elements = pattern.get('elements')\n elements.forEach((e) => {\n let local: NodePath<BabelTypes.Identifier>\n if (e.node?.type === 'Identifier') {\n local = e as NodePath<BabelTypes.Identifier>\n } else if (e.node?.type === 'RestElement') {\n local = e.get('argument') as NodePath<BabelTypes.Identifier>\n } else {\n return\n }\n\n if (shouldBeRemoved(local)) {\n ++referencesRemovedInThisPass\n e.remove()\n }\n })\n\n if (\n beforeCount !== referencesRemovedInThisPass &&\n pattern.get('elements').length < 1\n ) {\n path.remove()\n }\n }\n },\n FunctionDeclaration: sweepFunction,\n FunctionExpression: sweepFunction,\n ArrowFunctionExpression: sweepFunction,\n ImportSpecifier: sweepImport,\n ImportDefaultSpecifier: sweepImport,\n ImportNamespaceSpecifier: sweepImport,\n })\n } while (referencesRemovedInThisPass)\n}\n\nfunction getIdentifier(\n path: NodePath<\n | BabelTypes.FunctionDeclaration\n | BabelTypes.FunctionExpression\n | BabelTypes.ArrowFunctionExpression\n >,\n): NodePath<BabelTypes.Identifier> | null {\n const parentPath = path.parentPath\n if (parentPath.type === 'VariableDeclarator') {\n const variablePath = parentPath as NodePath<BabelTypes.VariableDeclarator>\n const name = variablePath.get('id')\n return name.node.type === 'Identifier'\n ? (name as NodePath<BabelTypes.Identifier>)\n : null\n }\n\n if (parentPath.type === 'AssignmentExpression') {\n const variablePath = parentPath as NodePath<BabelTypes.AssignmentExpression>\n const name = variablePath.get('left')\n return name.node.type === 'Identifier'\n ? (name as NodePath<BabelTypes.Identifier>)\n : null\n }\n\n if (path.node.type === 'ArrowFunctionExpression') {\n return null\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return path.node.id && path.node.id.type === 'Identifier'\n ? (path.get('id') as NodePath<BabelTypes.Identifier>)\n : null\n}\n\nfunction isIdentifierReferenced(\n ident: NodePath<BabelTypes.Identifier>,\n): boolean {\n const binding = ident.scope.getBinding(ident.node.name)\n if (binding?.referenced) {\n // Functions can reference themselves, so we need to check if there's a\n // binding outside the function scope or not.\n if (binding.path.type === 'FunctionDeclaration') {\n return !binding.constantViolations\n .concat(binding.referencePaths)\n // Check that every reference is contained within the function:\n .every((ref) => ref.findParent((parent) => parent === binding.path))\n }\n\n return true\n }\n return false\n}\n"],"names":["t"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { types as BabelTypes } from '@babel/core';
|
|
2
|
+
import type { NodePath } from '@babel/traverse';
|
|
3
|
+
type IdentifierPath = NodePath<BabelTypes.Identifier>;
|
|
4
|
+
/**
|
|
5
|
+
* @param refs - If provided, only these identifiers will be considered for removal.
|
|
6
|
+
*/
|
|
7
|
+
export declare const eliminateUnreferencedIdentifiers: (programPath: NodePath<BabelTypes.Program>, refs?: Set<IdentifierPath>) => void;
|
|
8
|
+
export {};
|