Skip to content

Commit

Permalink
Merge branch 'canary' into remove-server-actions-option
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] committed Oct 20, 2023
2 parents 1a841fb + 2f2e8e2 commit a12060a
Show file tree
Hide file tree
Showing 12 changed files with 410 additions and 156 deletions.
1 change: 1 addition & 0 deletions packages/next-swc/crates/next-core/src/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub async fn get_middleware_module(
"VAR_DEFINITION_PAGE" => "/middleware".to_string(),
},
indexmap! {},
indexmap! {},
)
.await?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub async fn get_app_page_entry(
"__next_app_require__" => "__turbopack_require__".to_string(),
"__next_app_load_chunk__" => " __turbopack_load__".to_string(),
},
indexmap! {},
)
.await?;

Expand Down Expand Up @@ -140,6 +141,7 @@ async fn wrap_edge_entry(
"VAR_USERLAND" => INNER.to_string(),
},
indexmap! {},
indexmap! {},
)
.await?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ pub async fn get_app_route_entry(
indexmap! {
"nextConfigOutput" => "\"\"".to_string(),
},
indexmap! {},
)
.await?;

Expand Down
10 changes: 8 additions & 2 deletions packages/next-swc/crates/next-core/src/next_pages/page_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,14 @@ pub async fn create_page_ssr_entry_module(
}

// Load the file from the next.js codebase.
let mut source =
load_next_js_template(template_file, project_root, replacements, indexmap! {}).await?;
let mut source = load_next_js_template(
template_file,
project_root,
replacements,
indexmap! {},
indexmap! {},
)
.await?;

// When we're building the instrumentation page (only when the
// instrumentation file conflicts with a page also labeled
Expand Down
65 changes: 65 additions & 0 deletions packages/next-swc/crates/next-core/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ pub async fn load_next_js_template(
project_path: Vc<FileSystemPath>,
replacements: IndexMap<&'static str, String>,
injections: IndexMap<&'static str, String>,
imports: IndexMap<&'static str, Option<String>>,
) -> Result<Vc<Box<dyn Source>>> {
let path = virtual_next_js_template_path(project_path, path.to_string());

Expand Down Expand Up @@ -531,6 +532,70 @@ pub async fn load_next_js_template(
)
}

// Replace the optional imports.
let mut imports_added = IndexSet::new();
for (key, import_path) in &imports {
let mut full = format!("// OPTIONAL_IMPORT:{}", key);
let namespace = if !content.contains(&full) {
full = format!("// OPTIONAL_IMPORT:* as {}", key);
if content.contains(&full) {
true
} else {
continue;
}
} else {
false
};

// Track all the imports to ensure that we're not missing any.
imports_added.insert(*key);

if let Some(path) = import_path {
content = content.replace(
&full,
&format!(
"import {}{} from {}",
if namespace { "* as " } else { "" },
key,
&StringifyJs(&path).to_string()
),
);
} else {
content = content.replace(&full, &format!("const {} = null", key));
}
}

// Check to see if there's any remaining imports.
let regex = lazy_regex::regex!("// OPTIONAL_IMPORT:(\\* as )?[A-Za-z0-9_]+");
let matches = regex
.find_iter(&content)
.map(|m| m.as_str().to_string())
.collect::<Vec<_>>();

if !matches.is_empty() {
bail!(
"Invariant: Expected to inject all imports, found {}",
matches.join(", "),
)
}

// Check to see if any import was provided but not used.
if imports_added.len() != imports.len() {
// Find the difference between the provided imports and the injected
// imports. This will let us notify the user of any imports that were
// not used but were provided.
let difference = imports
.keys()
.filter(|k| !imports_added.contains(*k))
.cloned()
.collect::<Vec<_>>();

bail!(
"Invariant: Expected to inject all imports, missing {} in template",
difference.join(", "),
)
}

// Ensure that the last line is a newline.
if !content.ends_with('\n') {
content.push('\n');
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/build/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ export function getEdgeServerEntry(opts: {
}

return {
import: `next-edge-ssr-loader?${stringify(loaderParams)}!`,
import: `next-edge-ssr-loader?${JSON.stringify(loaderParams)}!`,
// The Edge bundle includes the server in its entrypoint, so it has to
// be in the SSR layer — we later convert the page request to the RSC layer
// via a webpack rule.
Expand Down
60 changes: 57 additions & 3 deletions packages/next/src/build/load-entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,22 @@ const TEMPLATES_ESM_FOLDER = path.normalize(
* @param entrypoint the entrypoint to load
* @param replacements string replacements to perform
* @param injections code injections to perform
* @param imports optional imports to insert or set to null
* @returns the loaded file with the replacements
*/

export async function loadEntrypoint(
entrypoint:
| 'app-page'
| 'app-route'
| 'edge-app-route'
| 'edge-ssr'
| 'edge-ssr-app'
| 'middleware'
| 'pages'
| 'pages-api',
replacements: Record<`VAR_${string}`, string>,
injections?: Record<string, string>
injections?: Record<string, string>,
imports?: Record<string, string | null>
): Promise<string> {
const filepath = path.resolve(
path.join(TEMPLATES_ESM_FOLDER, `${entrypoint}.js`)
Expand All @@ -45,7 +48,7 @@ export async function loadEntrypoint(
// imports to be relative to the root of the `next` package.
let count = 0
file = file.replaceAll(
/(?:from "(\..*)"|import "(\..*)")/g,
/from "(\..*)"|import "(\..*)"/g,
function (_, fromRequest, importRequest) {
count++

Expand Down Expand Up @@ -174,5 +177,56 @@ export async function loadEntrypoint(
)
}

// Replace the optional imports.
const importsAdded = new Set<string>()
if (imports) {
// Track all the imports to ensure that we're not missing any.
file = file.replaceAll(
new RegExp(
`// OPTIONAL_IMPORT:(\\* as )?(${Object.keys(imports).join('|')})`,
'g'
),
(_, asNamespace = '', key) => {
if (!(key in imports)) {
throw new Error(`Invariant: Unexpected optional import ${key}`)
}

importsAdded.add(key)

if (imports[key]) {
return `import ${asNamespace}${key} from ${JSON.stringify(
imports[key]
)}`
} else {
return `const ${key} = null`
}
}
)
}

// Check to see if there's any remaining imports.
matches = file.match(/\/\/ OPTIONAL_IMPORT:(\* as )?[A-Za-z0-9_]+/g)
if (matches) {
throw new Error(
`Invariant: Expected to inject all imports, found ${matches.join(', ')}`
)
}

// Check to see if any import was provided but not used.
if (importsAdded.size !== Object.keys(imports ?? {}).length) {
// Find the difference between the provided imports and the injected
// imports. This will let us notify the user of any imports that were
// not used but were provided.
const difference = Object.keys(imports ?? {}).filter(
(key) => !importsAdded.has(key)
)

throw new Error(
`Invariant: Expected to inject all imports, missing ${difference.join(
', '
)} in template`
)
}

return file
}
79 changes: 79 additions & 0 deletions packages/next/src/build/templates/edge-ssr-app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import '../../server/web/globals'
import { adapter } from '../../server/web/adapter'
import { getRender } from '../webpack/loaders/next-edge-ssr-loader/render'
import { IncrementalCache } from '../../server/lib/incremental-cache'

import { renderToHTMLOrFlight as renderToHTML } from '../../server/app-render/app-render'
import * as pageMod from 'VAR_USERLAND'

import type { DocumentType } from '../../shared/lib/utils'
import type { BuildManifest } from '../../server/get-page-files'
import type { RequestData } from '../../server/web/types'
import type { NextConfigComplete } from '../../server/config-shared'

declare const incrementalCacheHandler: any
// OPTIONAL_IMPORT:incrementalCacheHandler

const Document: DocumentType = null!
const appMod = null
const errorMod = null
const error500Mod = null

// injected by the loader afterwards.
declare const sriEnabled: boolean
declare const isServerComponent: boolean
declare const dev: boolean
declare const serverActionsBodySizeLimit: any
declare const nextConfig: NextConfigComplete
// INJECT:sriEnabled
// INJECT:isServerComponent
// INJECT:dev
// INJECT:serverActionsBodySizeLimit
// INJECT:nextConfig

const maybeJSONParse = (str?: string) => (str ? JSON.parse(str) : undefined)

const buildManifest: BuildManifest = self.__BUILD_MANIFEST as any
const prerenderManifest = maybeJSONParse(self.__PRERENDER_MANIFEST)
const reactLoadableManifest = maybeJSONParse(self.__REACT_LOADABLE_MANIFEST)
const rscManifest = self.__RSC_MANIFEST?.['VAR_PAGE']
const rscServerManifest = maybeJSONParse(self.__RSC_SERVER_MANIFEST)
const subresourceIntegrityManifest = sriEnabled
? maybeJSONParse(self.__SUBRESOURCE_INTEGRITY_MANIFEST)
: undefined
const nextFontManifest = maybeJSONParse(self.__NEXT_FONT_MANIFEST)

const render = getRender({
pagesType: 'app',
dev,
page: 'VAR_PAGE',
appMod,
pageMod,
errorMod,
error500Mod,
Document,
buildManifest,
prerenderManifest,
renderToHTML,
reactLoadableManifest,
clientReferenceManifest: isServerComponent ? rscManifest : null,
serverActionsManifest: isServerComponent ? rscServerManifest : null,
serverActionsBodySizeLimit: isServerComponent
? serverActionsBodySizeLimit
: undefined,
subresourceIntegrityManifest,
config: nextConfig,
buildId: 'VAR_BUILD_ID',
nextFontManifest,
incrementalCacheHandler,
})

export const ComponentMod = pageMod

export default function nHandler(opts: { page: string; request: RequestData }) {
return adapter({
...opts,
IncrementalCache,
handler: render,
})
}

0 comments on commit a12060a

Please sign in to comment.