next-app-loader.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = exports.FILE_TYPES = void 0;
  6. var _webpackConfig = require("../../webpack-config");
  7. var _getModuleBuildInfo = require("./get-module-build-info");
  8. const FILE_TYPES = {
  9. layout: "layout",
  10. template: "template",
  11. error: "error",
  12. loading: "loading"
  13. };
  14. exports.FILE_TYPES = FILE_TYPES;
  15. async function createTreeCodeFromPath({ pagePath , resolve , resolveParallelSegments }) {
  16. const splittedPath = pagePath.split(/[\\/]/);
  17. const appDirPrefix = splittedPath[0];
  18. async function createSubtreePropsFromSegmentPath(segments) {
  19. const segmentPath = segments.join("/");
  20. // Existing tree are the children of the current segment
  21. const props = {};
  22. // We need to resolve all parallel routes in this level.
  23. const parallelSegments = [];
  24. if (segments.length === 0) {
  25. parallelSegments.push([
  26. "children",
  27. ""
  28. ]);
  29. } else {
  30. parallelSegments.push(...resolveParallelSegments(segmentPath));
  31. }
  32. for (const [parallelKey, parallelSegment] of parallelSegments){
  33. const parallelSegmentPath = segmentPath + "/" + parallelSegment;
  34. if (parallelSegment === "page") {
  35. const matchedPagePath = `${appDirPrefix}${parallelSegmentPath}`;
  36. const resolvedPagePath = await resolve(matchedPagePath);
  37. // Use '' for segment as it's the page. There can't be a segment called '' so this is the safest way to add it.
  38. props[parallelKey] = `['', {}, {layoutOrPagePath: ${JSON.stringify(resolvedPagePath)}, page: () => require(${JSON.stringify(resolvedPagePath)})}]`;
  39. continue;
  40. }
  41. const subtree = await createSubtreePropsFromSegmentPath([
  42. ...segments,
  43. parallelSegment,
  44. ]);
  45. // `page` is not included here as it's added above.
  46. const filePaths = await Promise.all(Object.values(FILE_TYPES).map(async (file)=>{
  47. return [
  48. file,
  49. await resolve(`${appDirPrefix}${parallelSegmentPath}/${file}`),
  50. ];
  51. }));
  52. props[parallelKey] = `[
  53. '${parallelSegment}',
  54. ${subtree},
  55. {
  56. ${filePaths.filter(([, filePath])=>filePath !== undefined).map(([file, filePath])=>{
  57. if (filePath === undefined) {
  58. return "";
  59. }
  60. return `${file === FILE_TYPES.layout ? `layoutOrPagePath: '${filePath}',` : ""}${file}: () => require(${JSON.stringify(filePath)}),`;
  61. }).join("\n")}
  62. }
  63. ]`;
  64. }
  65. return `{
  66. ${Object.entries(props).map(([key, value])=>`${key}: ${value}`).join(",\n")}
  67. }`;
  68. }
  69. const tree = await createSubtreePropsFromSegmentPath([]);
  70. return `const tree = ${tree}.children;`;
  71. }
  72. function createAbsolutePath(appDir, pathToTurnAbsolute) {
  73. return pathToTurnAbsolute.replace(/^private-next-app-dir/, appDir);
  74. }
  75. const nextAppLoader = async function nextAppLoader() {
  76. const { name , appDir , appPaths , pagePath , pageExtensions } = this.getOptions() || {};
  77. const buildInfo = (0, _getModuleBuildInfo).getModuleBuildInfo(this._module);
  78. buildInfo.route = {
  79. page: name.replace(/^app/, ""),
  80. absolutePagePath: createAbsolutePath(appDir, pagePath)
  81. };
  82. const extensions = pageExtensions.map((extension)=>`.${extension}`);
  83. const resolveOptions = {
  84. ..._webpackConfig.NODE_RESOLVE_OPTIONS,
  85. extensions
  86. };
  87. const resolve = this.getResolve(resolveOptions);
  88. const normalizedAppPaths = typeof appPaths === "string" ? [
  89. appPaths
  90. ] : appPaths || [];
  91. const resolveParallelSegments = (pathname)=>{
  92. const matched = {};
  93. for (const path of normalizedAppPaths){
  94. if (path.startsWith(pathname + "/")) {
  95. const restPath = path.slice(pathname.length + 1);
  96. const matchedSegment = restPath.split("/")[0];
  97. const matchedKey = matchedSegment.startsWith("@") ? matchedSegment.slice(1) : "children";
  98. matched[matchedKey] = matchedSegment;
  99. }
  100. }
  101. return Object.entries(matched);
  102. };
  103. const resolver = async (pathname)=>{
  104. try {
  105. const resolved = await resolve(this.rootContext, pathname);
  106. this.addDependency(resolved);
  107. return resolved;
  108. } catch (err) {
  109. const absolutePath = createAbsolutePath(appDir, pathname);
  110. for (const ext of extensions){
  111. const absolutePathWithExtension = `${absolutePath}${ext}`;
  112. this.addMissingDependency(absolutePathWithExtension);
  113. }
  114. if (err.message.includes("Can't resolve")) {
  115. return undefined;
  116. }
  117. throw err;
  118. }
  119. };
  120. const treeCode = await createTreeCodeFromPath({
  121. pagePath,
  122. resolve: resolver,
  123. resolveParallelSegments
  124. });
  125. const result = `
  126. export ${treeCode}
  127. export const AppRouter = require('next/dist/client/components/app-router.client.js').default
  128. export const LayoutRouter = require('next/dist/client/components/layout-router.client.js').default
  129. export const RenderFromTemplateContext = require('next/dist/client/components/render-from-template-context.client.js').default
  130. export const HotReloader = ${// Disable HotReloader component in production
  131. this.mode === "development" ? `require('next/dist/client/components/hot-reloader.client.js').default` : "null"}
  132. export const __next_app_webpack_require__ = __webpack_require__
  133. `;
  134. return result;
  135. };
  136. var _default = nextAppLoader;
  137. exports.default = _default;
  138. //# sourceMappingURL=next-app-loader.js.map