Skip to content

Commit

Permalink
port to swc ast
Browse files Browse the repository at this point in the history
  • Loading branch information
huozhi committed Jan 26, 2022
1 parent 7c37609 commit e62ea2a
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 78 deletions.
19 changes: 0 additions & 19 deletions packages/next-swc/crates/napi/src/parse.rs
Expand Up @@ -23,23 +23,16 @@ pub fn complete_parse<'a>(env: &Env, program: Program, _c: &Compiler) -> napi::R
env.create_string_from_std(s)
}


impl Task for ParseTask {
type Output = Program;
type JsValue = JsString;

fn compute(&mut self) -> napi::Result<Self::Output> {
// println!("compute");
let options: ParseOptions = deserialize_json(&self.options).convert_err()?;
// println!("compute.options");
let fm = self
.c
.cm
.new_source_file(self.filename.clone(), self.src.clone());
println!("target {:?}", options.target);
println!("syntax {:?}", options.syntax);
println!("is_module {:?}", options.is_module);
println!("comments {:?}", options.comments);
let program = try_with_handler(self.c.cm.clone(), false, |handler| {
self.c.parse_js(
fm,
Expand All @@ -62,25 +55,13 @@ impl Task for ParseTask {

#[js_function(3)]
pub fn parse(ctx: CallContext) -> napi::Result<JsObject> {
println!("get_compiler");
let c = get_compiler(&ctx);
println!("ctx.src");

let src = ctx.get_deserialized(0)?;

// let src = ctx.get::<JsString>(0)?.into_utf8()?;
println!("ctx.opts");
// let options = ctx.get_deserialized(1)?;
let options = ctx.get_buffer_as_string(1)?;
// let mut options: TransformOptions = cx.get_deserialized(2)?;
println!("ctx.filename");
let filename = ctx.get::<Either<JsString, JsUndefined>>(2)?;
println!("ctx.filename2");
let filename = if let Either::A(value) = filename {
println!("ctx.filename if");
FileName::Real(value.into_utf8()?.as_str()?.to_owned().into())
} else {
println!("ctx.filename else");
FileName::Anon
};

Expand Down
4 changes: 2 additions & 2 deletions packages/next/build/swc/index.js
Expand Up @@ -227,7 +227,7 @@ export async function bundle(options) {
return bindings.bundle(toBuffer(options))
}

export function parse(src, options) {
export async function parse(src, options) {
let bindings = loadBindingsSync()
return bindings.parse(src, options)
return bindings.parse(src, options).then((astStr) => JSON.parse(astStr))
}
57 changes: 23 additions & 34 deletions packages/next/build/webpack/loaders/next-flight-client-loader.ts
Expand Up @@ -5,7 +5,12 @@
* LICENSE file in the root directory of this source tree.
*/

import * as acorn from 'next/dist/compiled/acorn'
// import * as acorn from 'next/dist/compiled/acorn'
// TODO: add ts support for next-swc api
// @ts-ignore
import { parse } from '../../swc'
// @ts-ignore
import { getBaseSWCOptions } from '../../swc/options'

type ResolveContext = {
conditions: Array<string>
Expand All @@ -18,16 +23,12 @@ type ResolveFunction = (
resolve: ResolveFunction
) => { url: string } | Promise<{ url: string }>

type TransformSourceFunction = (url: string, callback: () => void) => void

type Source = string | ArrayBuffer | Uint8Array

let stashedResolve: null | ResolveFunction = null

function addExportNames(names: string[], node: any) {
switch (node.type) {
case 'Identifier':
names.push(node.name)
names.push(node.value)
return
case 'ObjectPattern':
for (let i = 0; i < node.properties.length; i++)
Expand Down Expand Up @@ -75,31 +76,24 @@ function resolveClientImport(
}

async function parseExportNamesInto(
resourcePath: string,
transformedSource: string,
names: Array<string>,
parentURL: string,
loadModule: TransformSourceFunction
names: Array<string>
): Promise<void> {
const { body } = acorn.parse(transformedSource, {
ecmaVersion: 11,
sourceType: 'module',
}) as any
const opts = getBaseSWCOptions({
filename: resourcePath,
globalWindow: true,
})

const { body } = await parse(transformedSource, {
...opts.jsc.parser,
isModule: true,
})
for (let i = 0; i < body.length; i++) {
const node = body[i]
switch (node.type) {
case 'ExportAllDeclaration':
if (node.exported) {
addExportNames(names, node.exported)
continue
} else {
const { url } = await resolveClientImport(
node.source.value,
parentURL
)
const source = ''
parseExportNamesInto(source, names, url, loadModule)
continue
}
// TODO: support export * from module path
// case 'ExportAllDeclaration':
case 'ExportDefaultDeclaration':
names.push('default')
continue
Expand Down Expand Up @@ -129,8 +123,8 @@ async function parseExportNamesInto(

export default async function transformSource(
this: any,
source: Source
): Promise<Source> {
source: string
): Promise<string> {
const { resourcePath, resourceQuery } = this

if (resourceQuery !== '?flight') return source
Expand All @@ -142,12 +136,7 @@ export default async function transformSource(
}

const names: string[] = []
await parseExportNamesInto(
transformedSource as string,
names,
url + resourceQuery,
this.loadModule
)
await parseExportNamesInto(resourcePath, transformedSource, names)

// next.js/packages/next/<component>.js
if (/[\\/]next[\\/](link|image)\.js$/.test(url)) {
Expand Down
29 changes: 11 additions & 18 deletions packages/next/build/webpack/loaders/next-flight-server-loader.ts
@@ -1,4 +1,4 @@
// import * as acorn from 'next/dist/compiled/acorn'
// TODO: add ts support for next-swc api
// @ts-ignore
import { parse } from '../../swc'
// @ts-ignore
Expand Down Expand Up @@ -43,29 +43,20 @@ async function parseImportsInfo(
}> {
const opts = getBaseSWCOptions({
filename: resourcePath,
// jest,
// development,
// hasReactRefresh,
globalWindow: isClientCompilation,
// nextConfig,
// resolvedBaseUrl,
// jsConfig,
})

const ast = await parse(source, { ...opts.jsc.parser, isModule: true })
const body = JSON.parse(ast).body

console.log('body', body)
const { body } = ast
const beginPos = ast.span.start
let transformedSource = ''
let lastIndex = 0
let defaultExportName = 'RSCComponent'

let defaultExportName
for (let i = 0; i < body.length; i++) {
const node = body[i]
switch (node.type) {
case 'ImportDeclaration': {
const importSource = node.source.value

if (!isClientCompilation) {
if (
!(
Expand All @@ -76,10 +67,11 @@ async function parseImportsInfo(
) {
continue
}
transformedSource += source.substring(
const importDeclarations = source.substring(
lastIndex,
node.source.start - 1
node.source.span.start - beginPos
)
transformedSource += importDeclarations
transformedSource += JSON.stringify(`${node.source.value}?flight`)
} else {
// For the client compilation, we skip all modules imports but
Expand All @@ -99,14 +91,13 @@ async function parseImportsInfo(
}
}

lastIndex = node.source.end
lastIndex = node.source.span.end - beginPos
imports.push(`require(${JSON.stringify(importSource)})`)
continue
}
case 'ExportDefaultDeclaration': {
const def = node.decl
if (def.type === 'Identifier') {
console.log('def', def)
defaultExportName = def.name
} else if (def.type === 'FunctionExpression') {
defaultExportName = def.identifier.value
Expand Down Expand Up @@ -167,7 +158,9 @@ export default async function transformSource(
const noop = `export const __rsc_noop__=()=>{${imports.join(';')}}`
const defaultExportNoop = isClientCompilation
? `export default function ${defaultExportName}(){}\n${defaultExportName}.__next_rsc__=1;`
: `${defaultExportName}.__next_rsc__=1;`
: defaultExportName
? `${defaultExportName}.__next_rsc__=1;`
: ''

const transformed = transformedSource + '\n' + noop + '\n' + defaultExportNoop

Expand Down
1 change: 0 additions & 1 deletion packages/next/server/dev/next-dev-server.ts
Expand Up @@ -672,7 +672,6 @@ export default class DevServer extends Server {
}
}

console.error(err)
if (!usedOriginalStack) {
if (type === 'warning') {
Log.warn(err + '')
Expand Down
@@ -0,0 +1 @@
export * from './client-exports'
@@ -0,0 +1,20 @@
export * from './client-exports'

// TODO: add exports all test case in pages
/**
import * as all from '../components/client-exports-all'
import * as allClient from '../components/client-exports-all.client'
export default function Page() {
const { a, b, c, d, e } = all
const { a: ac, b: bc, c: cc, d: dc, e: ec } = allClient
return (
<div>
<div id='server'>{a}{b}{c}{d}{e[0]}</div>
<div id='client'>{ac}{bc}{cc}{dc}{ec[0]}</div>
</div>
)
}
*/
@@ -0,0 +1,10 @@
const a = 'a'
const b = 'b'
const _c = 'c'
const _d = 'd'
const _e = 'e'
const _eArr = [_e]

export const c = _c
export { a, b }
export { _d as d, _eArr as e }
@@ -0,0 +1,25 @@
import * as all from '../components/client-exports-all'
import * as allClient from '../components/client-exports-all.client'

export default function Page() {
const { a, b, c, d, e } = all
const { a: ac, b: bc, c: cc, d: dc, e: ec } = allClient
return (
<div>
<div id="server">
{a}
{b}
{c}
{d}
{e[0]}
</div>
<div id="client">
{ac}
{bc}
{cc}
{dc}
{ec[0]}
</div>
</div>
)
}
@@ -0,0 +1,13 @@
import { a, b, c, d, e } from '../components/client-exports'

export default function Page() {
return (
<div>
{a}
{b}
{c}
{d}
{e[0]}
</div>
)
}
Expand Up @@ -3,10 +3,6 @@ import Foo from '../components/foo.client'
const envVar = process.env.ENV_VAR_TEST
const headerKey = 'x-next-test-client'

const a = () => {
console.log('a')
}

export default function Index({ header, router }) {
return (
<div>
Expand Down

0 comments on commit e62ea2a

Please sign in to comment.