record jsx factory symbols in classic mode (#3360)

* record jsx factory symbols

* merge factory/fragment when more than one part

* update test

* use existing functions, use, `memberListToComponentsIfDifferent`

* missing file

* fix defaults
This commit is contained in:
Dylan Conway
2023-06-20 19:29:20 -07:00
committed by GitHub
parent 5006435234
commit 6a1fbef8fd
5 changed files with 93 additions and 5 deletions

View File

@@ -506,7 +506,13 @@ pub const Bundler = struct {
switch (this.options.env.behavior) {
.prefix, .load_all => {
// Step 1. Load the project root.
var dir: *Fs.FileSystem.DirEntry = ((this.resolver.readDirInfo(this.fs.top_level_dir) catch return) orelse return).getEntries(this.resolver.generation) orelse return;
const dir_info = this.resolver.readDirInfo(this.fs.top_level_dir) catch return orelse return;
if (dir_info.tsconfig_json) |tsconfig| {
this.options.jsx = tsconfig.mergeJSX(this.options.jsx);
}
var dir = dir_info.getEntries(this.resolver.generation) orelse return;
// Process always has highest priority.
const was_production = this.options.production;

View File

@@ -15096,6 +15096,10 @@ fn NewParser_(
if (e_.tag) |_tag| {
break :tagger p.visitExpr(_tag);
} else {
if (p.options.jsx.runtime == .classic) {
break :tagger p.jsxStringsToMemberExpression(expr.loc, p.options.jsx.fragment) catch unreachable;
}
break :tagger p.jsxImport(.Fragment, expr.loc);
}
};
@@ -15169,9 +15173,11 @@ fn NewParser_(
i += @intCast(usize, @boolToInt(args[i].data != .e_missing));
}
const target = p.jsxStringsToMemberExpression(expr.loc, p.options.jsx.factory) catch unreachable;
// Call createElement()
return p.newExpr(E.Call{
.target = p.jsxImport(.createElement, expr.loc),
.target = target,
.args = ExprNodeList.init(args[0..i]),
// Enable tree shaking
.can_be_unwrapped_if_unused = !p.options.ignore_dce_annotations,

View File

@@ -1048,8 +1048,8 @@ pub const JSX = struct {
}
pub const Defaults = struct {
pub const Factory = &[_]string{"React.createElement"};
pub const Fragment = &[_]string{"React.Fragment"};
pub const Factory = &[_]string{ "React", "createElement" };
pub const Fragment = &[_]string{ "React", "Fragment" };
pub const ImportSourceDev = "react/jsx-dev-runtime";
pub const ImportSource = "react/jsx-runtime";
pub const JSXFunction = "jsx";

View File

@@ -323,4 +323,80 @@ describe("bundler", () => {
`,
},
});
itBundledDevAndProd("jsx/FactoryImport", {
todo: false,
files: {
"/index.jsx": /* js*/ `
import { h, fragment } from './jsx.ts';
const Fragment = 123;
import { print } from 'bun-test-helpers'
print([<div props={123}>Hello World</div>, <>Fragment</>])
`,
"/jsx.ts": /* ts */ `
export const h = () => 'hello factory';
export const fragment = () => 'hello fragment';
`,
...helpers,
},
target: "bun",
jsx: {
runtime: "classic",
factory: "h",
fragment: "fragment",
},
run: {
stdout: `
[\"hello factory\",\"hello factory\"]
`,
},
onAfterBundle(api) {
expect(api.readFile("out.js")).toContain("h(fragment");
},
});
itBundledDevAndProd("jsx/FactoryImportExplicitReactDefault", {
todo: false,
files: {
"/index.jsx": /* js*/ `
import { print } from 'bun-test-helpers'
import * as React from 'react';
print([<div props={123}>Hello World</div>, <>Fragment</>])
`,
...helpers,
},
target: "bun",
jsx: {
runtime: "classic",
factory: "React.createElement",
fragment: "React.Fragment",
},
onAfterBundle(api) {
expect(api.readFile("out.js")).toContain(" createElement");
expect(api.readFile("out.js")).toContain("(Fragment");
},
});
itBundledDevAndProd("jsx/FactoryImportExplicitReactDefaultExternal", {
todo: false,
files: {
"/index.jsx": /* js*/ `
import { print } from 'bun-test-helpers'
import * as React from 'react';
print([<div props={123}>Hello World</div>, <>Fragment</>])
`,
...helpers,
},
target: "bun",
jsx: {
runtime: "classic",
factory: "React.createElement",
fragment: "React.Fragment",
},
external: ["react"],
onAfterBundle(api) {
const file = api.readFile("out.js");
expect(file).toContain("React.createElement");
expect(file).toContain("React.Fragment");
expect(file).toContain('import * as React from "react"');
},
});
});

View File

@@ -393,7 +393,7 @@ describe("bundler", () => {
onAfterBundle(api) {
api
.expectFile("/Users/user/project/out.js")
.toContain(`console.log(c(F, null, c(\"div\", null), c(\"div\", null)));\n`);
.toContain(`console.log(R.c(R.F, null, R.c(\"div\", null), R.c(\"div\", null)));\n`);
},
});
itBundled("tsconfig/ReactJSXNotReact", {