UNPKG

next

Version:

The React Framework

225 lines (224 loc) • 9.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = transformSource; var _module = require("module"); var _swc = require("../../swc"); var _utils = require("./utils"); async function transformSource(source) { const { client: isClientCompilation , extensions } = this.getOptions(); const { resourcePath , resolve: resolveFn , context } = this; const resolver = (req)=>{ return new Promise((resolve, reject)=>{ resolveFn(context, req, (err, result)=>{ if (err) return reject(err); resolve(result); }); }); }; if (typeof source !== 'string') { throw new Error('Expected source to have been transformed to a string.'); } const isServerComponent = (0, _utils).createServerComponentFilter(extensions); const isClientComponent = (0, _utils).createClientComponentFilter(extensions); const hasAppliedFlightServerLoader = this.loaders.some((loader)=>{ return hasFlightLoader(loader.path, 'server'); }); const isServerExt = isServerComponent(resourcePath); if (!isClientCompilation) { // We only apply the loader to server components, or shared components that // are imported by a server component. if (!isServerExt && !hasAppliedFlightServerLoader) { return source; } } const { source: transformedSource , imports , isEsm , __N_SSP , pageRuntime , } = await parseModuleInfo({ resourcePath, source, extensions, isClientCompilation, isServerComponent, isClientComponent, resolver }); /** * For .server.js files, we handle this loader differently. * * Server compilation output: * (The content of the Server Component module will be kept.) * export const __next_rsc__ = { __webpack_require__, _: () => { ... }, server: true } * * Client compilation output: * (The content of the Server Component module will be removed.) * export const __next_rsc__ = { __webpack_require__, _: () => { ... }, server: false } */ const rscExports = { __next_rsc__: `{ __webpack_require__, _: () => { ${imports.map((importSource)=>`import(/* webpackMode: "eager" */ ${JSON.stringify(importSource)});` ).join('\n')} }, server: ${isServerExt ? 'true' : 'false'} }` }; if (isClientCompilation) { rscExports.default = 'function RSC() {}'; if (pageRuntime === 'edge') { // Currently for the Edge runtime, we treat all RSC pages as SSR pages. rscExports.__N_SSP = 'true'; } else { if (__N_SSP) { rscExports.__N_SSP = 'true'; } else { // Server component pages are always considered as SSG by default because // the flight data is needed for client navigation. rscExports.__N_SSG = 'true'; } } } const output = transformedSource + '\n' + (0, _utils).buildExports(rscExports, isEsm); return output; } function createFlightServerRequest(request, options) { return `next-flight-server-loader?${JSON.stringify(options)}!${request}`; } function hasFlightLoader(request, type) { return request.includes(`next-flight-${type}-loader`); } async function parseModuleInfo({ resourcePath , source , extensions , isClientCompilation , isServerComponent , isClientComponent , resolver }) { const ast = await (0, _swc).parse(source, { filename: resourcePath, isModule: 'unknown' }); const { type , body } = ast; let transformedSource = ''; let lastIndex = 0; let imports = []; let __N_SSP = false; let pageRuntime = null; let isBuiltinModule; let isNodeModuleImport; const isEsm = type === 'Module'; async function getModuleType(path) { const isBuiltinModule_ = _module.builtinModules.includes(path); const resolvedPath = isBuiltinModule_ ? path : await resolver(path); const isNodeModuleImport_ = resolvedPath.includes('/node_modules/'); return [ isBuiltinModule_, isNodeModuleImport_ ]; } function addClientImport(path) { if (isServerComponent(path) || hasFlightLoader(path, 'server')) { // If it's a server component, we recursively import its dependencies. imports.push(path); } else if (isClientComponent(path)) { // Client component. imports.push(path); } else { // Shared component. imports.push(createFlightServerRequest(path, { extensions, client: 1 })); } } for(let i = 0; i < body.length; i++){ const node = body[i]; switch(node.type){ case 'ImportDeclaration': const importSource = node.source.value; [isBuiltinModule, isNodeModuleImport] = await getModuleType(importSource); // matching node_module package but excluding react cores since react is required to be shared const isReactImports = [ 'react', 'react/jsx-runtime', 'react/jsx-dev-runtime', ].includes(importSource); if (!isClientCompilation) { // Server compilation for .server.js. if (isServerComponent(importSource)) { continue; } const importDeclarations = source.substring(lastIndex, node.source.span.start); if (isClientComponent(importSource)) { transformedSource += importDeclarations; transformedSource += JSON.stringify(`next-flight-client-loader!${importSource}`); imports.push(importSource); } else { // A shared component. It should be handled as a server component. const serverImportSource = isReactImports || isBuiltinModule ? importSource : createFlightServerRequest(importSource, { extensions }); transformedSource += importDeclarations; transformedSource += JSON.stringify(serverImportSource); // TODO: support handling RSC components from node_modules if (!isNodeModuleImport) { imports.push(importSource); } } } else { // For now we assume there is no .client.js inside node_modules. // TODO: properly handle this. if (isNodeModuleImport || isBuiltinModule) continue; addClientImport(importSource); } lastIndex = node.source.span.end; break; case 'ExportDeclaration': if (isClientCompilation) { var ref; // Keep `__N_SSG` and `__N_SSP` exports. if (((ref = node.declaration) === null || ref === void 0 ? void 0 : ref.type) === 'VariableDeclaration') { for (const declaration of node.declaration.declarations){ if (declaration.type === 'VariableDeclarator') { var ref1; if (((ref1 = declaration.id) === null || ref1 === void 0 ? void 0 : ref1.type) === 'Identifier') { const value = declaration.id.value; if (value === '__N_SSP') { __N_SSP = true; } else if (value === 'config') { var ref2; const props = declaration.init.properties; const runtimeKeyValue = props.find((prop)=>prop.key.value === 'runtime' ); const runtime = runtimeKeyValue === null || runtimeKeyValue === void 0 ? void 0 : (ref2 = runtimeKeyValue.value) === null || ref2 === void 0 ? void 0 : ref2.value; if (runtime === 'nodejs' || runtime === 'edge') { pageRuntime = runtime; } } } } } } } break; case 'ExportNamedDeclaration': if (isClientCompilation) { if (node.source) { // export { ... } from '...' const path = node.source.value; [isBuiltinModule, isNodeModuleImport] = await getModuleType(path); if (!isBuiltinModule && !isNodeModuleImport) { addClientImport(path); } } } break; default: break; } } if (!isClientCompilation) { transformedSource += source.substring(lastIndex); } return { source: transformedSource, imports, isEsm, __N_SSP, pageRuntime }; } //# sourceMappingURL=next-flight-server-loader.js.map