zero-com 1.10.2 → 1.12.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/lib/common.d.ts +5 -2
- package/lib/common.js +48 -9
- package/lib/rollup.js +17 -4
- package/lib/turbopack-loader.js +9 -3
- package/lib/webpack-loader.d.ts +2 -0
- package/lib/webpack-loader.js +5 -1
- package/lib/webpack.d.ts +1 -0
- package/lib/webpack.js +10 -2
- package/package.json +1 -1
package/lib/common.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type Replacement = {
|
|
|
8
8
|
export type Options = {
|
|
9
9
|
development?: boolean;
|
|
10
10
|
target?: 'client' | 'server';
|
|
11
|
+
contextDir?: string;
|
|
11
12
|
};
|
|
12
13
|
export type ServerFuncInfo = {
|
|
13
14
|
funcId: string;
|
|
@@ -32,7 +33,9 @@ export declare const getReplacements: (compilationId: string) => {
|
|
|
32
33
|
export declare const isFromLibrary: (callExpr: CallExpression, libraryName: string) => boolean;
|
|
33
34
|
export declare const resolveFilePath: (basePath: string) => string;
|
|
34
35
|
export declare const createProject: () => Project;
|
|
35
|
-
export declare const
|
|
36
|
+
export declare const mightNeedTransform: (content: string, filePath: string, registry: ServerFuncRegistry) => boolean;
|
|
37
|
+
export declare const buildRegistry: (contextDir: string, registry: ServerFuncRegistry, project?: Project) => void;
|
|
38
|
+
export declare const updateRegistryForFile: (filePath: string, contextDir: string, registry: ServerFuncRegistry, project?: Project) => void;
|
|
36
39
|
export declare const getImportedServerFunctions: (sourceFile: SourceFile, registry: ServerFuncRegistry) => Map<string, ServerFuncInfo>;
|
|
37
40
|
export declare const collectCallSiteReplacements: (sourceFile: SourceFile, importedFuncs: Map<string, ServerFuncInfo>) => Replacement[];
|
|
38
41
|
export declare const collectHandleCallReplacements: (sourceFile: SourceFile) => Replacement[];
|
|
@@ -53,6 +56,6 @@ export type TransformOptions = {
|
|
|
53
56
|
development?: boolean;
|
|
54
57
|
target?: 'client' | 'server';
|
|
55
58
|
};
|
|
56
|
-
export declare const transformSourceFile: (filePath: string, content: string, registry: ServerFuncRegistry, options?: TransformOptions) => TransformResult;
|
|
59
|
+
export declare const transformSourceFile: (filePath: string, content: string, registry: ServerFuncRegistry, options?: TransformOptions, project?: Project) => TransformResult;
|
|
57
60
|
export declare const emitToJs: (filePath: string, content: string) => string;
|
|
58
61
|
export declare const applyReplacements: (code: string, compilationId: string) => string;
|
package/lib/common.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.applyReplacements = exports.emitToJs = exports.transformSourceFile = exports.generateClientStubs = exports.appendRegistryCode = exports.applyReplacementsWithMap = exports.collectFuncCallReplacements = exports.collectSendCallReplacements = exports.collectHandleCallReplacements = exports.collectCallSiteReplacements = exports.getImportedServerFunctions = exports.buildRegistry = exports.createProject = exports.resolveFilePath = exports.isFromLibrary = exports.getReplacements = exports.generateCompilationId = exports.formatFuncIdName = exports.FILE_EXTENSIONS = exports.LIBRARY_NAME = exports.CALL_NAME = exports.HANDLE_NAME = exports.SERVER_FUNCTION_WRAPPER_NAME = exports.ZERO_COM_CONTEXT_STORAGE = exports.ZERO_COM_SERVER_REGISTRY = exports.ZERO_COM_CLIENT_CALL = void 0;
|
|
6
|
+
exports.applyReplacements = exports.emitToJs = exports.transformSourceFile = exports.generateClientStubs = exports.appendRegistryCode = exports.applyReplacementsWithMap = exports.collectFuncCallReplacements = exports.collectSendCallReplacements = exports.collectHandleCallReplacements = exports.collectCallSiteReplacements = exports.getImportedServerFunctions = exports.updateRegistryForFile = exports.buildRegistry = exports.mightNeedTransform = exports.createProject = exports.resolveFilePath = exports.isFromLibrary = exports.getReplacements = exports.generateCompilationId = exports.formatFuncIdName = exports.FILE_EXTENSIONS = exports.LIBRARY_NAME = exports.CALL_NAME = exports.HANDLE_NAME = exports.SERVER_FUNCTION_WRAPPER_NAME = exports.ZERO_COM_CONTEXT_STORAGE = exports.ZERO_COM_SERVER_REGISTRY = exports.ZERO_COM_CLIENT_CALL = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const magic_string_1 = __importDefault(require("magic-string"));
|
|
@@ -81,8 +81,32 @@ const getCalleeFullName = (callExpr) => {
|
|
|
81
81
|
return expr.getText();
|
|
82
82
|
return '';
|
|
83
83
|
};
|
|
84
|
+
// Fast pre-filter: check if a file might need transformation before doing expensive ts-morph parsing
|
|
85
|
+
const mightNeedTransform = (content, filePath, registry) => {
|
|
86
|
+
var _a;
|
|
87
|
+
if (content.includes(exports.LIBRARY_NAME))
|
|
88
|
+
return true;
|
|
89
|
+
if (registry.has(filePath))
|
|
90
|
+
return true;
|
|
91
|
+
if (registry.size === 0)
|
|
92
|
+
return false;
|
|
93
|
+
// Quick import scan: check if any imported path matches a registered server function file
|
|
94
|
+
const importPattern = /from\s+['"](\.[^'"]+)['"]/g;
|
|
95
|
+
let match;
|
|
96
|
+
while ((match = importPattern.exec(content)) !== null) {
|
|
97
|
+
const importedSegment = (_a = match[1].split('/').pop()) !== null && _a !== void 0 ? _a : '';
|
|
98
|
+
if (!importedSegment)
|
|
99
|
+
continue;
|
|
100
|
+
for (const registeredPath of registry.keys()) {
|
|
101
|
+
if (registeredPath.includes(importedSegment))
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
};
|
|
107
|
+
exports.mightNeedTransform = mightNeedTransform;
|
|
84
108
|
// Registry building
|
|
85
|
-
const buildRegistry = (contextDir, registry) => {
|
|
109
|
+
const buildRegistry = (contextDir, registry, project) => {
|
|
86
110
|
registry.clear();
|
|
87
111
|
const scanDirectory = (dir) => {
|
|
88
112
|
for (const entry of fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
@@ -91,15 +115,30 @@ const buildRegistry = (contextDir, registry) => {
|
|
|
91
115
|
scanDirectory(fullPath);
|
|
92
116
|
}
|
|
93
117
|
else if (entry.isFile() && exports.FILE_EXTENSIONS.slice(1).includes(path_1.default.extname(entry.name))) {
|
|
94
|
-
scanFileForServerFunctions(fullPath, contextDir, registry);
|
|
118
|
+
scanFileForServerFunctions(fullPath, contextDir, registry, project);
|
|
95
119
|
}
|
|
96
120
|
}
|
|
97
121
|
};
|
|
98
122
|
scanDirectory(contextDir);
|
|
99
123
|
};
|
|
100
124
|
exports.buildRegistry = buildRegistry;
|
|
101
|
-
const
|
|
102
|
-
|
|
125
|
+
const updateRegistryForFile = (filePath, contextDir, registry, project) => {
|
|
126
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
127
|
+
registry.delete(filePath);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const ext = path_1.default.extname(filePath);
|
|
131
|
+
if (!exports.FILE_EXTENSIONS.slice(1).includes(ext))
|
|
132
|
+
return;
|
|
133
|
+
scanFileForServerFunctions(filePath, contextDir, registry, project);
|
|
134
|
+
};
|
|
135
|
+
exports.updateRegistryForFile = updateRegistryForFile;
|
|
136
|
+
const scanFileForServerFunctions = (filePath, contextDir, registry, project) => {
|
|
137
|
+
const content = fs_1.default.readFileSync(filePath, 'utf8');
|
|
138
|
+
if (!content.includes(exports.LIBRARY_NAME))
|
|
139
|
+
return;
|
|
140
|
+
const proj = project !== null && project !== void 0 ? project : (0, exports.createProject)();
|
|
141
|
+
const sourceFile = proj.createSourceFile(filePath, content, { overwrite: true });
|
|
103
142
|
const fileRegistry = new Map();
|
|
104
143
|
for (const decl of sourceFile.getVariableDeclarations()) {
|
|
105
144
|
if (!decl.isExported())
|
|
@@ -274,10 +313,10 @@ const generateClientStubs = (fileRegistry) => {
|
|
|
274
313
|
return stubs;
|
|
275
314
|
};
|
|
276
315
|
exports.generateClientStubs = generateClientStubs;
|
|
277
|
-
const transformSourceFile = (filePath, content, registry, options = {}) => {
|
|
316
|
+
const transformSourceFile = (filePath, content, registry, options = {}, project) => {
|
|
278
317
|
const { development = true, target } = options;
|
|
279
|
-
const
|
|
280
|
-
const sourceFile =
|
|
318
|
+
const proj = project !== null && project !== void 0 ? project : (0, exports.createProject)();
|
|
319
|
+
const sourceFile = proj.createSourceFile(filePath, content, { overwrite: true });
|
|
281
320
|
const fileRegistry = registry.get(filePath);
|
|
282
321
|
const isServerFunctionFile = fileRegistry && fileRegistry.size > 0;
|
|
283
322
|
if (target === 'client' && isServerFunctionFile) {
|
|
@@ -308,7 +347,7 @@ const transformSourceFile = (filePath, content, registry, options = {}) => {
|
|
|
308
347
|
if (replacements.length > 0) {
|
|
309
348
|
const { code, map } = (0, exports.applyReplacementsWithMap)(content, replacements, filePath);
|
|
310
349
|
// Create a new source file from the transformed code to append registry
|
|
311
|
-
const transformedSourceFile =
|
|
350
|
+
const transformedSourceFile = proj.createSourceFile(filePath + '.transformed', code, { overwrite: true });
|
|
312
351
|
return { content: (0, exports.appendRegistryCode)(transformedSourceFile, fileRegistry), transformed: true, map };
|
|
313
352
|
}
|
|
314
353
|
return { content: (0, exports.appendRegistryCode)(sourceFile, fileRegistry), transformed: true };
|
package/lib/rollup.js
CHANGED
|
@@ -17,10 +17,12 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
17
17
|
const path_1 = __importDefault(require("path"));
|
|
18
18
|
const common_1 = require("./common");
|
|
19
19
|
function zeroComRollupPlugin(options = {}) {
|
|
20
|
-
const { development = true, target } = options;
|
|
20
|
+
const { development = true, target, contextDir: optContextDir } = options;
|
|
21
21
|
const compilationId = (0, common_1.generateCompilationId)();
|
|
22
22
|
const registry = new Map();
|
|
23
|
+
const project = (0, common_1.createProject)();
|
|
23
24
|
let isVite = false;
|
|
25
|
+
let scanDir = optContextDir !== null && optContextDir !== void 0 ? optContextDir : process.cwd();
|
|
24
26
|
return {
|
|
25
27
|
name: 'zero-com-rollup-plugin',
|
|
26
28
|
// Vite-only hook — detect that we're running inside Vite
|
|
@@ -28,13 +30,20 @@ function zeroComRollupPlugin(options = {}) {
|
|
|
28
30
|
isVite = true;
|
|
29
31
|
},
|
|
30
32
|
buildStart() {
|
|
31
|
-
|
|
33
|
+
if (!optContextDir)
|
|
34
|
+
scanDir = process.cwd();
|
|
35
|
+
(0, common_1.buildRegistry)(scanDir, registry, project);
|
|
32
36
|
for (const fileRegistry of registry.values()) {
|
|
33
37
|
for (const info of fileRegistry.values()) {
|
|
34
38
|
console.log(`[ZeroComRollupPlugin] ${info.funcId}`);
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
},
|
|
42
|
+
watchChange(id) {
|
|
43
|
+
if (!common_1.FILE_EXTENSIONS.slice(1).includes(path_1.default.extname(id)))
|
|
44
|
+
return;
|
|
45
|
+
(0, common_1.updateRegistryForFile)(id, scanDir, registry, project);
|
|
46
|
+
},
|
|
38
47
|
// Rollup path: resolveId marks files, load transforms them.
|
|
39
48
|
// Skipped in Vite because meta doesn't propagate from resolveId to load.
|
|
40
49
|
resolveId(source, importer, opts) {
|
|
@@ -61,7 +70,9 @@ function zeroComRollupPlugin(options = {}) {
|
|
|
61
70
|
if (!((_b = (_a = this.getModuleInfo(id)) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.needsTransform) || !fs_1.default.existsSync(id))
|
|
62
71
|
return null;
|
|
63
72
|
const content = fs_1.default.readFileSync(id, 'utf8');
|
|
64
|
-
|
|
73
|
+
if (!(0, common_1.mightNeedTransform)(content, id, registry))
|
|
74
|
+
return null;
|
|
75
|
+
const result = (0, common_1.transformSourceFile)(id, content, registry, { development, target }, project);
|
|
65
76
|
if (!result.transformed)
|
|
66
77
|
return null;
|
|
67
78
|
console.log(`[ZeroComRollupPlugin] Transformed: ${path_1.default.relative(process.cwd(), id)}`);
|
|
@@ -76,12 +87,14 @@ function zeroComRollupPlugin(options = {}) {
|
|
|
76
87
|
return null;
|
|
77
88
|
if (id[0] === '\0' || id.includes('node_modules') || !/\.(ts|tsx|js|jsx|mjs)$/.test(id))
|
|
78
89
|
return null;
|
|
90
|
+
if (!(0, common_1.mightNeedTransform)(code, id, registry))
|
|
91
|
+
return null;
|
|
79
92
|
// Derive effective target: explicit option takes precedence, otherwise infer from Vite's ssr flag
|
|
80
93
|
const ssr = typeof viteOptions === 'object' && viteOptions !== null && 'ssr' in viteOptions
|
|
81
94
|
? viteOptions.ssr
|
|
82
95
|
: undefined;
|
|
83
96
|
const effectiveTarget = target !== null && target !== void 0 ? target : (ssr === false ? 'client' : ssr === true ? 'server' : undefined);
|
|
84
|
-
const result = (0, common_1.transformSourceFile)(id, code, registry, { development, target: effectiveTarget });
|
|
97
|
+
const result = (0, common_1.transformSourceFile)(id, code, registry, { development, target: effectiveTarget }, project);
|
|
85
98
|
if (!result.transformed)
|
|
86
99
|
return null;
|
|
87
100
|
console.log(`[ZeroComRollupPlugin] Transformed: ${path_1.default.relative(process.cwd(), id)}`);
|
package/lib/turbopack-loader.js
CHANGED
|
@@ -6,9 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.default = turbopackLoader;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const common_1 = require("./common");
|
|
9
|
-
// Module-level cache: registry
|
|
9
|
+
// Module-level cache: registry and project are built once and reused across invocations
|
|
10
10
|
let cachedRegistry = null;
|
|
11
11
|
let cachedRootDir = null;
|
|
12
|
+
let cachedProject = null;
|
|
12
13
|
function turbopackLoader(source) {
|
|
13
14
|
var _a;
|
|
14
15
|
const options = this.getOptions();
|
|
@@ -17,16 +18,21 @@ function turbopackLoader(source) {
|
|
|
17
18
|
const development = (_a = options.development) !== null && _a !== void 0 ? _a : true;
|
|
18
19
|
// Lazily build and cache the registry on first invocation or if rootDir changes
|
|
19
20
|
if (!cachedRegistry || cachedRootDir !== rootDir) {
|
|
21
|
+
cachedProject = (0, common_1.createProject)();
|
|
20
22
|
cachedRegistry = new Map();
|
|
21
23
|
cachedRootDir = rootDir;
|
|
22
|
-
(0, common_1.buildRegistry)(rootDir, cachedRegistry);
|
|
24
|
+
(0, common_1.buildRegistry)(rootDir, cachedRegistry, cachedProject);
|
|
23
25
|
for (const fileRegistry of cachedRegistry.values()) {
|
|
24
26
|
for (const info of fileRegistry.values()) {
|
|
25
27
|
console.log(`[TurbopackLoader] ${info.funcId}`);
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
|
-
|
|
31
|
+
if (!(0, common_1.mightNeedTransform)(source, filePath, cachedRegistry)) {
|
|
32
|
+
this.callback(null, source);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const result = (0, common_1.transformSourceFile)(filePath, source, cachedRegistry, { development, target: options.target }, cachedProject !== null && cachedProject !== void 0 ? cachedProject : undefined);
|
|
30
36
|
if (!result.transformed) {
|
|
31
37
|
this.callback(null, source);
|
|
32
38
|
return;
|
package/lib/webpack-loader.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { LoaderContext } from 'webpack';
|
|
2
|
+
import { Project } from 'ts-morph';
|
|
2
3
|
import { ServerFuncRegistry } from './common';
|
|
3
4
|
export interface ZeroComLoaderOptions {
|
|
4
5
|
registry: ServerFuncRegistry;
|
|
6
|
+
project?: Project;
|
|
5
7
|
development: boolean;
|
|
6
8
|
target?: 'client' | 'server';
|
|
7
9
|
}
|
package/lib/webpack-loader.js
CHANGED
|
@@ -9,10 +9,14 @@ const common_1 = require("./common");
|
|
|
9
9
|
function zeroComLoader(source) {
|
|
10
10
|
const options = this.getOptions();
|
|
11
11
|
const filePath = this.resourcePath;
|
|
12
|
+
if (!(0, common_1.mightNeedTransform)(source, filePath, options.registry)) {
|
|
13
|
+
this.callback(null, source);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
12
16
|
const result = (0, common_1.transformSourceFile)(filePath, source, options.registry, {
|
|
13
17
|
development: options.development,
|
|
14
18
|
target: options.target
|
|
15
|
-
});
|
|
19
|
+
}, options.project);
|
|
16
20
|
if (!result.transformed) {
|
|
17
21
|
this.callback(null, source);
|
|
18
22
|
return;
|
package/lib/webpack.d.ts
CHANGED
package/lib/webpack.js
CHANGED
|
@@ -5,21 +5,29 @@ const common_1 = require("./common");
|
|
|
5
5
|
class ZeroComWebpackPlugin {
|
|
6
6
|
constructor(options = {}) {
|
|
7
7
|
this.registry = new Map();
|
|
8
|
+
this.project = (0, common_1.createProject)();
|
|
8
9
|
this.options = Object.assign({ development: true }, options);
|
|
9
10
|
this.compilationId = (0, common_1.generateCompilationId)();
|
|
10
11
|
}
|
|
11
12
|
apply(compiler) {
|
|
13
|
+
var _a;
|
|
12
14
|
const pluginName = ZeroComWebpackPlugin.name;
|
|
13
15
|
const { webpack } = compiler;
|
|
16
|
+
const contextDir = (_a = this.options.contextDir) !== null && _a !== void 0 ? _a : compiler.context;
|
|
14
17
|
// Build registry before compilation
|
|
15
18
|
compiler.hooks.beforeCompile.tap(pluginName, () => {
|
|
16
|
-
(0, common_1.buildRegistry)(
|
|
19
|
+
(0, common_1.buildRegistry)(contextDir, this.registry, this.project);
|
|
17
20
|
for (const fileRegistry of this.registry.values()) {
|
|
18
21
|
for (const info of fileRegistry.values()) {
|
|
19
22
|
console.log(`[ZeroComWebpackPlugin] ${info.funcId}`);
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
});
|
|
26
|
+
// Incrementally update registry when a file changes during watch mode
|
|
27
|
+
compiler.hooks.invalid.tap(pluginName, (fileName) => {
|
|
28
|
+
if (fileName)
|
|
29
|
+
(0, common_1.updateRegistryForFile)(fileName, contextDir, this.registry, this.project);
|
|
30
|
+
});
|
|
23
31
|
// Add loader rule for TypeScript/JavaScript files
|
|
24
32
|
const loaderPath = require.resolve('./webpack-loader');
|
|
25
33
|
const loaderRule = {
|
|
@@ -28,7 +36,7 @@ class ZeroComWebpackPlugin {
|
|
|
28
36
|
enforce: 'pre',
|
|
29
37
|
use: [{
|
|
30
38
|
loader: loaderPath,
|
|
31
|
-
options: { registry: this.registry, development: this.options.development, target: this.options.target }
|
|
39
|
+
options: { registry: this.registry, project: this.project, development: this.options.development, target: this.options.target }
|
|
32
40
|
}]
|
|
33
41
|
};
|
|
34
42
|
compiler.options.module.rules.unshift(loaderRule);
|