UNPKG

next

Version:

The React Framework

154 lines (153 loc) 6.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = transformSource; var _swc = require("../../swc"); var _utils = require("../../utils"); var _utils1 = require("./utils"); async function transformSource(source) { const { client: isClientCompilation , pageExtensions } = this.getOptions(); const { resourcePath , resourceQuery } = this; if (typeof source !== 'string') { throw new Error('Expected source to have been transformed to a string.'); } // We currently assume that all components are shared components (unsuffixed) // from node_modules. if (resourcePath.includes('/node_modules/')) { return source; } const rawRawPageExtensions = (0, _utils).getRawPageExtensions(pageExtensions); const isServerComponent = createServerComponentFilter(rawRawPageExtensions); const isClientComponent = createClientComponentFilter(rawRawPageExtensions); if (!isClientCompilation) { // We only apply the loader to server components, or shared components that // are imported by a server component. if (!isServerComponent(resourcePath) && resourceQuery !== '?__sc_server__') { return source; } } const { source: transformedSource , imports , isEsm , } = await parseModuleInfo({ resourcePath, source, isClientCompilation, isServerComponent, isClientComponent }); /** * 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__, _: () => { ... } } * * Client compilation output: * (The content of the Server Component module will be removed.) * export const __next_rsc__ = { __webpack_require__, _: () => { ... } } */ const rscExports = { __next_rsc__: `{ __webpack_require__, _: () => {\n${imports}\n} }`, __next_rsc_server__: isServerComponent(resourcePath) ? 'true' : 'false' }; if (isClientCompilation) { rscExports['default'] = 'function RSC() {}'; } const output = transformedSource + '\n' + (0, _utils1).buildExports(rscExports, isEsm); return output; } const imageExtensions = [ 'jpg', 'jpeg', 'png', 'webp', 'avif' ]; const createClientComponentFilter = (pageExtensions)=>{ // Special cases for Next.js APIs that are considered as client components: // - .client.[ext] // - next/link, next/image // - .[imageExt] const regex = new RegExp('(' + `\\.client(\\.(${pageExtensions.join('|')}))?|` + `next/link|next/image|` + `\\.(${imageExtensions.join('|')})` + ')$'); return (importSource)=>regex.test(importSource) ; }; const createServerComponentFilter = (pageExtensions)=>{ const regex = new RegExp(`\\.server(\\.(${pageExtensions.join('|')}))?$`); return (importSource)=>regex.test(importSource) ; }; async function parseModuleInfo({ resourcePath , source , isClientCompilation , isServerComponent , isClientComponent }) { const ast = await (0, _swc).parse(source, { filename: resourcePath, isModule: 'unknown' }); const { type , body } = ast; let transformedSource = ''; let lastIndex = 0; let imports = ''; const isEsm = type === 'Module'; for(let i = 0; i < body.length; i++){ const node = body[i]; switch(node.type){ case 'ImportDeclaration': { const importSource = node.source.value; if (!isClientCompilation) { // Server compilation for .server.js. if (isServerComponent(importSource)) { continue; } const importDeclarations = source.substring(lastIndex, node.source.span.start); if (isClientComponent(importSource)) { // A client component. It should be loaded as module reference. transformedSource += importDeclarations; transformedSource += JSON.stringify(`${importSource}?__sc_client__`); imports += `require(${JSON.stringify(importSource)})\n`; } else { // FIXME // case: 'react' // Avoid module resolution error like Cannot find `./?__rsc_server__` in react/package.json // cases: 'react/jsx-runtime', 'react/jsx-dev-runtime' // This is a special case to avoid the Duplicate React error. // Since we already include React in the SSR runtime, // here we can't create a new module with the ?__rsc_server__ query. if ([ 'react', 'react/jsx-runtime', 'react/jsx-dev-runtime' ].includes(importSource)) { continue; } // A shared component. It should be handled as a server // component. transformedSource += importDeclarations; transformedSource += JSON.stringify(`${importSource}?__sc_server__`); } } else { // For the client compilation, we skip all modules imports but // always keep client components in the bundle. All client components // have to be imported from either server or client components. if (!(isClientComponent(importSource) || isServerComponent(importSource))) { continue; } imports += `require(${JSON.stringify(importSource)})\n`; } lastIndex = node.source.span.end; break; } default: break; } } if (!isClientCompilation) { transformedSource += source.substring(lastIndex); } return { source: transformedSource, imports, isEsm }; } //# sourceMappingURL=next-flight-server-loader.js.map