dinou 2.0.1 → 2.0.2
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/package.json
CHANGED
|
@@ -12,6 +12,7 @@ function reactClientManifestPlugin({
|
|
|
12
12
|
} = {}) {
|
|
13
13
|
const manifest = {};
|
|
14
14
|
const clientModules = new Set();
|
|
15
|
+
const serverModules = new Set();
|
|
15
16
|
|
|
16
17
|
function parseExports(code) {
|
|
17
18
|
const ast = parser.parse(code, {
|
|
@@ -77,6 +78,102 @@ function reactClientManifestPlugin({
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
function getImports(code, baseFilePath, visited = new Set()) {
|
|
82
|
+
if (visited.has(baseFilePath)) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
visited.add(baseFilePath);
|
|
86
|
+
|
|
87
|
+
const ast = parser.parse(code, {
|
|
88
|
+
sourceType: "module",
|
|
89
|
+
plugins: ["jsx", "typescript"],
|
|
90
|
+
});
|
|
91
|
+
const imports = new Set();
|
|
92
|
+
|
|
93
|
+
traverse(ast, {
|
|
94
|
+
ImportDeclaration(nodePath) {
|
|
95
|
+
const source = nodePath.node.source.value;
|
|
96
|
+
if (source.startsWith(".")) {
|
|
97
|
+
let absImportPath = path.resolve(path.dirname(baseFilePath), source);
|
|
98
|
+
const extensions = [".js", ".jsx", ".ts", ".tsx"];
|
|
99
|
+
if (!extensions.some((ext) => absImportPath.endsWith(ext))) {
|
|
100
|
+
for (const ext of extensions) {
|
|
101
|
+
const potentialPath = absImportPath + ext;
|
|
102
|
+
if (existsSync(potentialPath)) {
|
|
103
|
+
absImportPath = potentialPath;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (existsSync(absImportPath)) {
|
|
109
|
+
imports.add(absImportPath);
|
|
110
|
+
try {
|
|
111
|
+
const importCode = readFileSync(absImportPath, "utf8");
|
|
112
|
+
const nestedImports = getImports(
|
|
113
|
+
importCode,
|
|
114
|
+
absImportPath,
|
|
115
|
+
visited
|
|
116
|
+
);
|
|
117
|
+
nestedImports.forEach((nestedPath) => imports.add(nestedPath));
|
|
118
|
+
} catch (err) {
|
|
119
|
+
console.warn(
|
|
120
|
+
`[react-client-manifest] Could not read import: ${absImportPath}`,
|
|
121
|
+
err.message
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
console.warn(
|
|
126
|
+
`[react-client-manifest] Import path not found: ${absImportPath}`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return Array.from(imports);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function isPageOrLayout(absPath) {
|
|
137
|
+
const fileName = path.basename(absPath);
|
|
138
|
+
return fileName.startsWith("page.") || fileName.startsWith("layout.");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function isAsyncDefaultExport(code) {
|
|
142
|
+
const ast = parser.parse(code, {
|
|
143
|
+
sourceType: "module",
|
|
144
|
+
plugins: ["jsx", "typescript"],
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
let isAsync = false;
|
|
148
|
+
|
|
149
|
+
traverse(ast, {
|
|
150
|
+
ExportDefaultDeclaration(path) {
|
|
151
|
+
let decl = path.node.declaration;
|
|
152
|
+
|
|
153
|
+
if (decl.type === "Identifier") {
|
|
154
|
+
const binding = path.scope.getBinding(decl.name);
|
|
155
|
+
if (binding && binding.path) {
|
|
156
|
+
decl = binding.path.node;
|
|
157
|
+
if (decl.type === "VariableDeclarator") {
|
|
158
|
+
decl = decl.init;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (
|
|
164
|
+
decl &&
|
|
165
|
+
(decl.type === "FunctionDeclaration" ||
|
|
166
|
+
decl.type === "ArrowFunctionExpression" ||
|
|
167
|
+
decl.type === "FunctionExpression")
|
|
168
|
+
) {
|
|
169
|
+
isAsync = decl.async;
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
return isAsync;
|
|
175
|
+
}
|
|
176
|
+
|
|
80
177
|
return {
|
|
81
178
|
name: "react-client-manifest",
|
|
82
179
|
async buildStart() {
|
|
@@ -93,12 +190,23 @@ function reactClientManifestPlugin({
|
|
|
93
190
|
if (isClientModule) {
|
|
94
191
|
clientModules.add(normalizedPath);
|
|
95
192
|
updateManifestForModule(absPath, code, true);
|
|
96
|
-
|
|
97
193
|
this.emitFile({
|
|
98
194
|
type: "chunk",
|
|
99
195
|
id: absPath,
|
|
100
196
|
name: path.basename(absPath, path.extname(absPath)),
|
|
101
197
|
});
|
|
198
|
+
} else if (isPageOrLayout(absPath)) {
|
|
199
|
+
if (!isAsyncDefaultExport(code)) {
|
|
200
|
+
this.warn(
|
|
201
|
+
`[react-client-manifest] The file ${normalizedPath} is a page or layout without "use client" directive, but its default export is not an async function. Add "use client" if it's a client component, or make the default export async if it's a server component.`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
serverModules.add(normalizedPath);
|
|
205
|
+
this.addWatchFile(absPath);
|
|
206
|
+
const imports = getImports(code, absPath);
|
|
207
|
+
for (const importPath of imports) {
|
|
208
|
+
this.addWatchFile(importPath);
|
|
209
|
+
}
|
|
102
210
|
}
|
|
103
211
|
}
|
|
104
212
|
},
|
|
@@ -119,6 +227,7 @@ function reactClientManifestPlugin({
|
|
|
119
227
|
}
|
|
120
228
|
}
|
|
121
229
|
clientModules.delete(normalizedId);
|
|
230
|
+
serverModules.delete(normalizedId);
|
|
122
231
|
return;
|
|
123
232
|
}
|
|
124
233
|
const code = readFileSync(id, "utf8");
|
|
@@ -128,19 +237,33 @@ function reactClientManifestPlugin({
|
|
|
128
237
|
|
|
129
238
|
if (isClientModule) {
|
|
130
239
|
clientModules.add(normalizedId);
|
|
240
|
+
serverModules.delete(normalizedId);
|
|
131
241
|
this.addWatchFile(id);
|
|
132
242
|
} else {
|
|
133
243
|
clientModules.delete(normalizedId);
|
|
244
|
+
if (isPageOrLayout(id)) {
|
|
245
|
+
if (!isAsyncDefaultExport(code)) {
|
|
246
|
+
this.warn(
|
|
247
|
+
`[react-client-manifest] The file ${normalizedId} is a page or layout without "use client" directive, but its default export is not an async function. Add "use client" if it's a client component, or make the default export async if it's a server component.`
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
serverModules.add(normalizedId);
|
|
251
|
+
this.addWatchFile(id);
|
|
252
|
+
const imports = getImports(code, id);
|
|
253
|
+
for (const importPath of imports) {
|
|
254
|
+
this.addWatchFile(importPath);
|
|
255
|
+
}
|
|
256
|
+
} else {
|
|
257
|
+
serverModules.delete(normalizedId);
|
|
258
|
+
}
|
|
134
259
|
}
|
|
135
260
|
},
|
|
136
261
|
generateBundle(outputOptions, bundle) {
|
|
137
262
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
138
263
|
if (chunk.type !== "chunk") continue;
|
|
139
|
-
|
|
140
264
|
for (const modulePath of Object.keys(chunk.modules)) {
|
|
141
265
|
const absModulePath = path.resolve(modulePath);
|
|
142
266
|
const baseFileUrl = pathToFileURL(absModulePath).href;
|
|
143
|
-
|
|
144
267
|
for (const manifestKey in manifest) {
|
|
145
268
|
if (manifestKey.startsWith(baseFileUrl)) {
|
|
146
269
|
manifest[manifestKey].id = "/" + fileName;
|
|
@@ -148,7 +271,6 @@ function reactClientManifestPlugin({
|
|
|
148
271
|
}
|
|
149
272
|
}
|
|
150
273
|
}
|
|
151
|
-
|
|
152
274
|
const serialized = JSON.stringify(manifest, null, 2);
|
|
153
275
|
mkdirSync(dirname(manifestPath), { recursive: true });
|
|
154
276
|
writeFileSync(manifestPath, serialized);
|