Skip to content

Commit

Permalink
switch to use swc transform
Browse files Browse the repository at this point in the history
  • Loading branch information
shuding committed Sep 16, 2022
1 parent 464ba8d commit a11dbee
Show file tree
Hide file tree
Showing 18 changed files with 126 additions and 55 deletions.
82 changes: 54 additions & 28 deletions packages/next-swc/crates/core/src/react_server_components.rs
Expand Up @@ -28,8 +28,8 @@ impl Config {
}

#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Options {
#[serde(default)]
pub is_server: bool,
}

Expand Down Expand Up @@ -88,17 +88,25 @@ impl<C: Comments> ReactServerComponents<'_, C> {
finished_directives = true;
}

match &*stmt.as_expr().unwrap().expr {
Expr::Lit(Lit::Str(Str { value, .. })) => {
if value.to_string() == "client" {
is_client_entry = true;
match stmt.as_expr() {
Some(expr_stmt) => {
match &*expr_stmt.expr {
Expr::Lit(Lit::Str(Str { value, .. })) => {
if value.to_string() == "client" {
is_client_entry = true;

// Remove the directive.
return false;
// Remove the directive.
return false;
}
}
_ => {
// Other expression types.
finished_directives = true;
}
}
}
_ => {
// Other expression types.
None => {
// Not an expression.
finished_directives = true;
}
}
Expand Down Expand Up @@ -151,29 +159,47 @@ impl<C: Comments> ReactServerComponents<'_, C> {
prepend_stmts(
&mut module.body,
vec![
ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl {
span: DUMMY_SP,
specifiers: vec![ImportSpecifier::Named(ImportNamedSpecifier {
kind: VarDeclKind::Const,
decls: vec![VarDeclarator {
span: DUMMY_SP,
local: proxy_ident.clone(),
imported: None,
is_type_only: false,
})],
src: Str {
span: DUMMY_SP,
raw: None,
value: "private-next-rsc-mod-ref-proxy".into(),
},
type_only: Default::default(),
asserts: Default::default(),
})),
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(ExportDefaultExpr {
name: Pat::Object(ObjectPat {
span: DUMMY_SP,
props: vec![ObjectPatProp::Assign(AssignPatProp {
span: DUMMY_SP,
key: proxy_ident.clone(),
value: None,
})],
optional: false,
type_ann: None,
}),
init: Some(Box::new(Expr::Call(CallExpr {
span: DUMMY_SP,
callee: quote_ident!("require").as_callee(),
args: vec![quote_str!("private-next-rsc-mod-ref-proxy").as_arg()],
type_args: Default::default(),
}))),
definite: false,
}],
declare: false,
}))),
ModuleItem::Stmt(Stmt::Expr(ExprStmt {
span: DUMMY_SP,
expr: Box::new(Expr::Call(CallExpr {
expr: Box::new(Expr::Assign(AssignExpr {
span: DUMMY_SP,
callee: proxy_ident.clone().as_callee(),
args: vec![filepath.as_arg()],
type_args: None,
left: PatOrExpr::Expr(Box::new(Expr::Member(MemberExpr {
span: DUMMY_SP,
obj: Box::new(Expr::Ident(quote_ident!("module"))),
prop: MemberProp::Ident(quote_ident!("exports")),
}))),
op: op!("="),
right: Box::new(Expr::Call(CallExpr {
span: DUMMY_SP,
callee: quote_ident!("createProxy").as_callee(),
args: vec![filepath.as_arg()],
type_args: Default::default(),
})),
})),
})),
]
Expand Down
@@ -1,4 +1,3 @@
// This is a comment.
/* __next_internal_client_entry_do_not_use__ */
import { createProxy } from "private-next-rsc-mod-ref-proxy";
export default createProxy("/some-project/src/some-file.js");
/* __next_internal_client_entry_do_not_use__ */ const { createProxy } = require("private-next-rsc-mod-ref-proxy");
module.exports = createProxy("/some-project/src/some-file.js");
8 changes: 8 additions & 0 deletions packages/next/build/swc/options.js
Expand Up @@ -32,6 +32,7 @@ function getBaseSWCOptions({
resolvedBaseUrl,
jsConfig,
swcCacheDir,
isServerLayer,
}) {
const parserConfig = getParserOptions({ filename, jsConfig })
const paths = jsConfig?.compilerOptions?.paths
Expand Down Expand Up @@ -117,6 +118,11 @@ function getBaseSWCOptions({
modularizeImports: nextConfig?.experimental?.modularizeImports,
relay: nextConfig?.compiler?.relay,
emotion: getEmotionOptions(nextConfig, development),
serverComponents: nextConfig?.experimental?.serverComponents
? {
isServer: !!isServerLayer,
}
: false,
}
}

Expand Down Expand Up @@ -203,6 +209,7 @@ export function getLoaderSWCOptions({
filename,
development,
isServer,
isServerLayer,
pagesDir,
isPageFile,
hasReactRefresh,
Expand All @@ -222,6 +229,7 @@ export function getLoaderSWCOptions({
jsConfig,
// resolvedBaseUrl,
swcCacheDir,
isServerLayer,
})

const isNextDist = nextDistPath.test(filename)
Expand Down
30 changes: 23 additions & 7 deletions packages/next/build/webpack-config.ts
Expand Up @@ -1499,13 +1499,13 @@ export default async function getBaseWebpackConfig(
loader: 'next-flight-server-loader',
},
},
{
test: clientComponentRegex,
issuerLayer: WEBPACK_LAYERS.server,
use: {
loader: 'next-flight-client-loader',
},
},
// {
// test: clientComponentRegex,
// issuerLayer: WEBPACK_LAYERS.server,
// use: {
// loader: 'next-flight-client-loader',
// },
// },
// _app should be treated as a client component as well as all its dependencies.
{
test: new RegExp(`_app\\.(${rawPageExtensions.join('|')})$`),
Expand Down Expand Up @@ -1548,6 +1548,22 @@ export default async function getBaseWebpackConfig(
issuerLayer: WEBPACK_LAYERS.middleware,
use: getBabelOrSwcLoader(),
},
...(hasServerComponents
? [
{
// ...codeCondition,
test: clientComponentRegex,
issuerLayer: WEBPACK_LAYERS.server,
use: {
...defaultLoaders.babel,
options: {
...defaultLoaders.babel.options,
isServerLayer: true,
},
},
},
]
: []),
{
...codeCondition,
use:
Expand Down
4 changes: 3 additions & 1 deletion packages/next/build/webpack/loaders/next-swc-loader.js
Expand Up @@ -38,6 +38,7 @@ async function loaderTransform(parentTrace, source, inputSourceMap) {

const {
isServer,
isServerLayer,
pagesDir,
hasReactRefresh,
nextConfig,
Expand All @@ -50,7 +51,8 @@ async function loaderTransform(parentTrace, source, inputSourceMap) {
const swcOptions = getLoaderSWCOptions({
pagesDir,
filename,
isServer: isServer,
isServer,
isServerLayer,
isPageFile,
development: this.mode === 'development',
hasReactRefresh,
Expand Down
21 changes: 6 additions & 15 deletions packages/next/build/webpack/loaders/utils.ts
Expand Up @@ -3,23 +3,14 @@ import { getPageStaticInfo } from '../../analysis/get-page-static-info'
export const defaultJsFileExtensions = ['js', 'mjs', 'jsx', 'ts', 'tsx']
const imageExtensions = ['jpg', 'jpeg', 'png', 'webp', 'avif']
const nextClientComponents = [
'link',
'image',
// TODO-APP: check if this affects the regex
'future/image',
'head',
'script',
'dynamic',
'dist/client/link',
'dist/client/image',
'dist/client/future/image',
'dist/shared/lib/head',
'dist/client/script',
'dist/shared/lib/dynamic',
]

const NEXT_BUILT_IN_CLIENT_RSC_REGEX = new RegExp(
`[\\\\/]next[\\\\/](${nextClientComponents.join('|')})\\.js$`
)

export function isNextBuiltinClientComponent(resourcePath: string) {
return NEXT_BUILT_IN_CLIENT_RSC_REGEX.test(resourcePath)
}

export function buildExports(moduleExports: any, isESM: boolean) {
let ret = ''
Object.keys(moduleExports).forEach((key) => {
Expand Down
2 changes: 2 additions & 0 deletions packages/next/client/components/app-router.client.tsx
@@ -1,3 +1,5 @@
'client'

import type { PropsWithChildren, ReactElement, ReactNode } from 'react'
import React, { useEffect, useMemo, useCallback } from 'react'
import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-webpack'
Expand Down
2 changes: 2 additions & 0 deletions packages/next/client/components/hot-reloader.client.tsx
@@ -1,3 +1,5 @@
'client'

import {
useCallback,
useContext,
Expand Down
2 changes: 2 additions & 0 deletions packages/next/client/components/layout-router.client.tsx
@@ -1,3 +1,5 @@
'client'

import React, { useContext, useEffect, useRef } from 'react'
import type {
ChildProp,
Expand Down
@@ -1,3 +1,5 @@
'client'

import React, { useContext } from 'react'
import { TemplateContext } from '../../shared/lib/app-router-context'

Expand Down
2 changes: 2 additions & 0 deletions packages/next/client/future/image.tsx
@@ -1,3 +1,5 @@
'client'

import React, {
useRef,
useEffect,
Expand Down
2 changes: 2 additions & 0 deletions packages/next/client/image.tsx
@@ -1,3 +1,5 @@
'client'

import React, {
useRef,
useEffect,
Expand Down
2 changes: 2 additions & 0 deletions packages/next/client/link.tsx
@@ -1,3 +1,5 @@
'client'

import React from 'react'
import { UrlObject } from 'url'
import {
Expand Down
2 changes: 2 additions & 0 deletions packages/next/client/script.tsx
@@ -1,3 +1,5 @@
'client'

import React, { useEffect, useContext, useRef } from 'react'
import { ScriptHTMLAttributes } from 'react'
import { HeadManagerContext } from '../shared/lib/head-manager-context'
Expand Down
2 changes: 2 additions & 0 deletions packages/next/shared/lib/dynamic.tsx
@@ -1,3 +1,5 @@
'client'

import React from 'react'
import Loadable from './loadable'

Expand Down
2 changes: 2 additions & 0 deletions packages/next/shared/lib/head.tsx
@@ -1,3 +1,5 @@
'client'

import React, { useContext } from 'react'
import Effect from './side-effect'
import { AmpStateContext } from './amp-context'
Expand Down
9 changes: 8 additions & 1 deletion packages/next/taskfile-swc.js
Expand Up @@ -108,9 +108,16 @@ module.exports = function (task) {
...swcOptions,
}

const output = yield transform(file.data.toString('utf-8'), options)
const source = file.data.toString('utf-8')
const output = yield transform(source, options)
const ext = path.extname(file.base)

// Make sure the output content keeps the `"client"` directive.
// TODO: Remove this once SWC fixes the issue.
if (source.startsWith("'client'")) {
output.code = '"client";\n' + output.code
}

// Replace `.ts|.tsx` with `.js` in files with an extension
if (ext) {
const extRegex = new RegExp(ext.replace('.', '\\.') + '$', 'i')
Expand Down
2 changes: 2 additions & 0 deletions test/e2e/app-dir/rsc-basic/app/root-style-registry.client.js
@@ -1,3 +1,5 @@
'client'

import React from 'react'
import { StyleRegistry, createStyleRegistry } from 'styled-jsx'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'
Expand Down

0 comments on commit a11dbee

Please sign in to comment.