Skip to content

Commit

Permalink
Merge branch 'canary' into upgrade-playwright
Browse files Browse the repository at this point in the history
  • Loading branch information
ijjk committed Dec 7, 2022
2 parents 37f85e1 + 2332272 commit 7919831
Show file tree
Hide file tree
Showing 44 changed files with 334 additions and 366 deletions.
1 change: 0 additions & 1 deletion packages/next-swc/crates/core/src/lib.rs
Expand Up @@ -185,7 +185,6 @@ where
next_dynamic::next_dynamic(
opts.is_development,
opts.is_server,
opts.server_components.is_some(),
file.name.clone(),
opts.pages_dir.clone()
),
Expand Down
62 changes: 2 additions & 60 deletions packages/next-swc/crates/core/src/next_dynamic.rs
Expand Up @@ -5,26 +5,23 @@ use pathdiff::diff_paths;
use swc_core::{
common::{errors::HANDLER, FileName, DUMMY_SP},
ecma::ast::{
ArrayLit, ArrowExpr, BinExpr, BinaryOp, BlockStmtOrExpr, Bool, CallExpr, Callee, Expr,
ArrayLit, ArrowExpr, BinExpr, BinaryOp, BlockStmtOrExpr, CallExpr, Callee, Expr,
ExprOrSpread, Id, Ident, ImportDecl, ImportSpecifier, KeyValueProp, Lit, MemberExpr,
MemberProp, Null, ObjectLit, Prop, PropName, PropOrSpread, Str, Tpl,
MemberProp, ObjectLit, Prop, PropName, PropOrSpread, Str, Tpl,
},
ecma::atoms::js_word,
ecma::utils::ExprFactory,
ecma::visit::{Fold, FoldWith},
};

pub fn next_dynamic(
is_development: bool,
is_server: bool,
is_server_components: bool,
filename: FileName,
pages_dir: Option<PathBuf>,
) -> impl Fold {
NextDynamicPatcher {
is_development,
is_server,
is_server_components,
pages_dir,
filename,
dynamic_bindings: vec![],
Expand All @@ -37,7 +34,6 @@ pub fn next_dynamic(
struct NextDynamicPatcher {
is_development: bool,
is_server: bool,
is_server_components: bool,
pages_dir: Option<PathBuf>,
filename: FileName,
dynamic_bindings: Vec<Id>,
Expand Down Expand Up @@ -233,70 +229,16 @@ impl Fold for NextDynamicPatcher {
value: generated,
})))];

let mut has_ssr_false = false;
let mut has_suspense = false;

if expr.args.len() == 2 {
if let Expr::Object(ObjectLit {
props: options_props,
..
}) = &*expr.args[1].expr
{
for prop in options_props.iter() {
if let Some(KeyValueProp { key, value }) = match prop {
PropOrSpread::Prop(prop) => match &**prop {
Prop::KeyValue(key_value_prop) => Some(key_value_prop),
_ => None,
},
_ => None,
} {
if let Some(Ident {
sym,
span: _,
optional: _,
}) = match key {
PropName::Ident(ident) => Some(ident),
_ => None,
} {
if sym == "ssr" {
if let Some(Lit::Bool(Bool {
value: false,
span: _,
})) = value.as_lit()
{
has_ssr_false = true
}
}
if sym == "suspense" {
if let Some(Lit::Bool(Bool {
value: true,
span: _,
})) = value.as_lit()
{
has_suspense = true
}
}
}
}
}
props.extend(options_props.iter().cloned());
}
}

// Don't strip the `loader` argument if suspense is true
// See https://github.com/vercel/next.js/issues/36636 for background.

// Also don't strip the `loader` argument for server components (both
// server/client layers), since they're aliased to a
// React.lazy implementation.
if has_ssr_false
&& !has_suspense
&& self.is_server
&& !self.is_server_components
{
expr.args[0] = Lit::Null(Null { span: DUMMY_SP }).as_arg();
}

let second_arg = ExprOrSpread {
spread: None,
expr: Box::new(Expr::Object(ObjectLit {
Expand Down
1 change: 0 additions & 1 deletion packages/next-swc/crates/core/tests/errors.rs
Expand Up @@ -46,7 +46,6 @@ fn next_dynamic_errors(input: PathBuf) {
next_dynamic(
true,
false,
false,
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
Some("/some-project/src".into()),
)
Expand Down
3 changes: 0 additions & 3 deletions packages/next-swc/crates/core/tests/fixture.rs
Expand Up @@ -49,7 +49,6 @@ fn next_dynamic_fixture(input: PathBuf) {
next_dynamic(
true,
false,
false,
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
Some("/some-project/src".into()),
)
Expand All @@ -62,7 +61,6 @@ fn next_dynamic_fixture(input: PathBuf) {
syntax(),
&|_tr| {
next_dynamic(
false,
false,
false,
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
Expand All @@ -79,7 +77,6 @@ fn next_dynamic_fixture(input: PathBuf) {
next_dynamic(
false,
true,
false,
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
Some("/some-project/src".into()),
)
Expand Down
@@ -1,23 +1,21 @@
import dynamic from 'next/dynamic';
const DynamicComponentWithCustomLoading = dynamic(()=>import('../components/hello')
, {
const DynamicComponentWithCustomLoading = dynamic(()=>import('../components/hello'), {
loadableGenerated: {
modules: [
"some-file.js -> " + "../components/hello"
]
},
loading: ()=><p >...</p>
});
const DynamicClientOnlyComponent = dynamic(null, {
const DynamicClientOnlyComponent = dynamic(()=>import('../components/hello'), {
loadableGenerated: {
modules: [
"some-file.js -> " + "../components/hello"
]
},
ssr: false
});
const DynamicClientOnlyComponentWithSuspense = dynamic(()=>import('../components/hello')
, {
const DynamicClientOnlyComponentWithSuspense = dynamic(()=>import('../components/hello'), {
loadableGenerated: {
modules: [
"some-file.js -> " + "../components/hello"
Expand Down
@@ -1,11 +1,10 @@
import dynamic from 'next/dynamic';
const DynamicComponent = dynamic(null, {
const DynamicComponent = dynamic(()=>handleImport(import('./components/hello')), {
loadableGenerated: {
modules: [
"some-file.js -> " + "./components/hello"
]
},
loading: ()=>null
,
loading: ()=>null,
ssr: false
});
2 changes: 1 addition & 1 deletion packages/next/build/swc/options.js
Expand Up @@ -128,7 +128,7 @@ function getBaseSWCOptions({
? {
isServer: !!isServerLayer,
}
: false,
: undefined,
}
}

Expand Down
18 changes: 0 additions & 18 deletions packages/next/build/webpack-config.ts
Expand Up @@ -1707,26 +1707,8 @@ export default async function getBaseWebpackConfig(
},
]
: []),
// Alias `next/dynamic` to React.lazy implementation for RSC
...(hasServerComponents
? [
{
test: codeCondition.test,
issuerLayer(layer: string) {
return (
layer === WEBPACK_LAYERS.client ||
layer === WEBPACK_LAYERS.server
)
},
resolve: {
alias: {
// Alias `next/dynamic` to React.lazy implementation for RSC
[require.resolve('next/dynamic')]: require.resolve(
'next/dist/client/components/dynamic'
),
},
},
},
{
// Alias react-dom for ReactDOM.preload usage.
// Alias react for switching between default set and share subset.
Expand Down
31 changes: 19 additions & 12 deletions packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts
Expand Up @@ -5,25 +5,32 @@
*/

export function pitch(this: any) {
const content = this.fs.readFileSync(this.resourcePath)
this.data.__checksum = (
typeof content === 'string' ? Buffer.from(content) : content
).toString('hex')
if (process.env.NODE_ENV !== 'production') {
const content = this.fs.readFileSync(this.resourcePath)
this.data.__checksum = (
typeof content === 'string' ? Buffer.from(content) : content
).toString('hex')
}
}

const NextServerCSSLoader = function (this: any, content: string) {
this.cacheable && this.cacheable()

const isCSSModule = this.resourcePath.match(/\.module\.(css|sass|scss)$/)
if (isCSSModule) {
return (
content +
'\nmodule.exports.__checksum = ' +
JSON.stringify(this.data.__checksum)
)
// Only add the checksum during development.
if (process.env.NODE_ENV !== 'production') {
const isCSSModule = this.resourcePath.match(/\.module\.(css|sass|scss)$/)
if (isCSSModule) {
return (
content +
'\nmodule.exports.__checksum = ' +
JSON.stringify(this.data.__checksum)
)
}

return `export default ${JSON.stringify(this.data.__checksum)}`
}

return `export default ${JSON.stringify(this.data.__checksum)}`
return content
}

export default NextServerCSSLoader
29 changes: 26 additions & 3 deletions packages/next/client/app-index.tsx
Expand Up @@ -7,6 +7,7 @@ import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-we

import { HeadManagerContext } from '../shared/lib/head-manager-context'
import { GlobalLayoutRouterContext } from '../shared/lib/app-router-context'
import { NEXT_DYNAMIC_NO_SSR_CODE } from '../shared/lib/no-ssr-error'

/// <reference types="react-dom/experimental" />

Expand Down Expand Up @@ -116,6 +117,23 @@ if (document.readyState === 'loading') {
DOMContentLoaded()
}

function onRecoverableError(err: any) {
// Using default react onRecoverableError
// x-ref: https://github.com/facebook/react/blob/d4bc16a7d69eb2ea38a88c8ac0b461d5f72cdcab/packages/react-dom/src/client/ReactDOMRoot.js#L83
const defaultOnRecoverableError =
typeof reportError === 'function'
? // In modern browsers, reportError will dispatch an error event,
// emulating an uncaught JavaScript error.
reportError
: (error: any) => {
window.console.error(error)
}

// Skip certain custom errors which are not expected to be reported on client
if (err.digest === NEXT_DYNAMIC_NO_SSR_CODE) return
defaultOnRecoverableError(err)
}

const nextServerDataLoadingGlobal = ((self as any).__next_f =
(self as any).__next_f || [])
nextServerDataLoadingGlobal.forEach(nextServerDataCallback)
Expand Down Expand Up @@ -193,7 +211,9 @@ export function hydrate() {
if (rootLayoutMissingTagsError) {
const reactRootElement = document.createElement('div')
document.body.appendChild(reactRootElement)
const reactRoot = (ReactDOMClient as any).createRoot(reactRootElement)
const reactRoot = (ReactDOMClient as any).createRoot(reactRootElement, {
onRecoverableError,
})

reactRoot.render(
<GlobalLayoutRouterContext.Provider
Expand Down Expand Up @@ -234,11 +254,14 @@ export function hydrate() {
</StrictModeIfEnabled>
)

const options = {
onRecoverableError,
}
const isError = document.documentElement.id === '__next_error__'
const reactRoot = isError
? (ReactDOMClient as any).createRoot(appElement)
? (ReactDOMClient as any).createRoot(appElement, options)
: (React as any).startTransition(() =>
(ReactDOMClient as any).hydrateRoot(appElement, reactEl)
(ReactDOMClient as any).hydrateRoot(appElement, reactEl, options)
)
if (isError) {
reactRoot.render(reactEl)
Expand Down
19 changes: 0 additions & 19 deletions packages/next/client/components/dynamic.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions packages/next/client/components/layout-router.tsx
Expand Up @@ -359,7 +359,7 @@ class RedirectErrorBoundary extends React.Component<
}

static getDerivedStateFromError(error: any) {
if (error.digest?.startsWith('NEXT_REDIRECT')) {
if (error?.digest?.startsWith('NEXT_REDIRECT')) {
const url = error.digest.split(';')[1]
return { redirect: url }
}
Expand Down Expand Up @@ -400,7 +400,7 @@ class NotFoundErrorBoundary extends React.Component<
}

static getDerivedStateFromError(error: any) {
if (error.digest === 'NEXT_NOT_FOUND') {
if (error?.digest === 'NEXT_NOT_FOUND') {
return { notFoundTriggered: true }
}
// Re-throw if error is not for 404
Expand Down
9 changes: 8 additions & 1 deletion packages/next/client/index.tsx
Expand Up @@ -43,6 +43,7 @@ import {
PathnameContextProviderAdapter,
} from '../shared/lib/router/adapters'
import { SearchParamsContext } from '../shared/lib/hooks-client-context'
import { NEXT_DYNAMIC_NO_SSR_CODE } from '../shared/lib/no-ssr-error'

/// <reference types="react-dom/experimental" />

Expand Down Expand Up @@ -510,7 +511,13 @@ function renderReactElement(
const reactEl = fn(shouldHydrate ? markHydrateComplete : markRenderComplete)
if (!reactRoot) {
// Unlike with createRoot, you don't need a separate root.render() call here
reactRoot = ReactDOM.hydrateRoot(domEl, reactEl)
reactRoot = ReactDOM.hydrateRoot(domEl, reactEl, {
onRecoverableError(err: any) {
// Skip certain custom errors which are not expected to throw on client
if (err.message === NEXT_DYNAMIC_NO_SSR_CODE) return
throw err
},
})
// TODO: Remove shouldHydrate variable when React 18 is stable as it can depend on `reactRoot` existing
shouldHydrate = false
} else {
Expand Down

0 comments on commit 7919831

Please sign in to comment.