mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
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:
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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"');
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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", {
|
||||
|
||||
Reference in New Issue
Block a user