diff options
author | 2023-06-20 19:29:20 -0700 | |
---|---|---|
committer | 2023-06-20 19:29:20 -0700 | |
commit | 6a1fbef8fdc8d2bb12a0124b5730d5682a4360d5 (patch) | |
tree | 68e7613eb244144800549b8ee7eda0fb2c2e4cb1 | |
parent | 50064352346f48da74f66caca9d30b81a77c89b9 (diff) | |
download | bun-6a1fbef8fdc8d2bb12a0124b5730d5682a4360d5.tar.gz bun-6a1fbef8fdc8d2bb12a0124b5730d5682a4360d5.tar.zst bun-6a1fbef8fdc8d2bb12a0124b5730d5682a4360d5.zip |
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
-rw-r--r-- | src/bundler.zig | 8 | ||||
-rw-r--r-- | src/js_parser.zig | 8 | ||||
-rw-r--r-- | src/options.zig | 4 | ||||
-rw-r--r-- | test/bundler/bundler_jsx.test.ts | 76 | ||||
-rw-r--r-- | test/bundler/esbuild/tsconfig.test.ts | 2 |
5 files changed, 93 insertions, 5 deletions
diff --git a/src/bundler.zig b/src/bundler.zig index 3c796b576..fb0a11be7 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -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; diff --git a/src/js_parser.zig b/src/js_parser.zig index 51627a134..33a8cef6d 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -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, diff --git a/src/options.zig b/src/options.zig index a39c9fc6c..08eb7b4b7 100644 --- a/src/options.zig +++ b/src/options.zig @@ -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"; diff --git a/test/bundler/bundler_jsx.test.ts b/test/bundler/bundler_jsx.test.ts index a77eec0d0..5288701d6 100644 --- a/test/bundler/bundler_jsx.test.ts +++ b/test/bundler/bundler_jsx.test.ts @@ -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"'); + }, + }); }); diff --git a/test/bundler/esbuild/tsconfig.test.ts b/test/bundler/esbuild/tsconfig.test.ts index e83a1eb23..b09a0d281 100644 --- a/test/bundler/esbuild/tsconfig.test.ts +++ b/test/bundler/esbuild/tsconfig.test.ts @@ -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", { |