aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--demos/hello-next/bun-framework-next/package.json7
-rw-r--r--demos/hello-next/pages/index.tsx19
-rw-r--r--src/http.zig34
-rw-r--r--src/js_parser/js_parser.zig165
-rw-r--r--src/options.zig4
-rw-r--r--src/resolver/package_json.zig26
-rw-r--r--src/runtime.version2
-rw-r--r--src/runtime/hmr.ts1
8 files changed, 178 insertions, 80 deletions
diff --git a/demos/hello-next/bun-framework-next/package.json b/demos/hello-next/bun-framework-next/package.json
index 7aa47a88f..901391964 100644
--- a/demos/hello-next/bun-framework-next/package.json
+++ b/demos/hello-next/bun-framework-next/package.json
@@ -1,6 +1,6 @@
{
"name": "bun-framework-next",
- "version": "0.0.0-6",
+ "version": "0.0.0-8",
"description": "",
"main": "package.json",
"framework": {
@@ -69,5 +69,8 @@
},
"author": "",
"license": "ISC",
- "dependencies": {}
+ "dependencies": {
+ "buffer": "^6.0.3",
+ "path": "^0.12.7"
+ }
}
diff --git a/demos/hello-next/pages/index.tsx b/demos/hello-next/pages/index.tsx
index 2866bad51..621f2c401 100644
--- a/demos/hello-next/pages/index.tsx
+++ b/demos/hello-next/pages/index.tsx
@@ -3,13 +3,11 @@ import Image from "next/image";
import styles from "../styles/Home.module.css";
import Link from "next/link";
-import Title from "../components/Title";
-
export default function Home() {
return (
<div className={styles.container}>
<Head>
- <title>Create Next App</title>
+ <title>Create Next Ap123p</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
@@ -40,15 +38,12 @@ export default function Home() {
<h2>Learn &rarr;</h2>
<p>Learn about Next.js in an interactive course with quizzes!</p>
</a>
-
- <a
- href="https://github.com/vercel/next.js/tree/master/examples"
- className={styles.card}
- >
- <h2>Examples &rarr;</h2>
- <p>Discover and deploy boilerplate example Next.js projects.</p>
- </a>
-
+ <Link href="/hi">
+ <a className={styles.card}>
+ <h2>Examples &rarr;</h2>
+ <p>Discover and deploy boilerplate example Next.js projects.</p>
+ </a>
+ </Link>
<a
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
diff --git a/src/http.zig b/src/http.zig
index 2848d78d4..9db247073 100644
--- a/src/http.zig
+++ b/src/http.zig
@@ -50,13 +50,6 @@ usingnamespace @import("./javascript/jsc/bindings/exports.zig");
const Router = @import("./router.zig");
pub const Watcher = watcher.NewWatcher(*Server);
-const ENABLE_LOGGER = false;
-pub fn println(comptime fmt: string, args: anytype) void {
- // if (ENABLE_LOGGER) {
- Output.println(fmt, args);
- // }
-}
-
const HTTPStatusCode = u10;
const URLPath = @import("./http/url_path.zig");
@@ -1079,7 +1072,7 @@ pub const RequestContext = struct {
ctx.appendHeader("Sec-WebSocket-Protocol", "bun-hmr");
try ctx.writeStatus(101);
try ctx.flushHeaders();
- Output.println("101 - Websocket connected.", .{});
+ Output.prettyln("<r><green>101<r><d> Hot Module Reloading connected.", .{});
Output.flush();
var cmd: Api.WebsocketCommand = undefined;
@@ -1988,9 +1981,30 @@ pub const Server = struct {
const status = req_ctx.status orelse @intCast(HTTPStatusCode, 500);
if (req_ctx.log.msgs.items.len == 0) {
- println("{d} – {s} {s} as {s}", .{ status, @tagName(req_ctx.method), req.path, req_ctx.mime_type.value });
+ switch (status) {
+ 101, 199...399 => {
+ Output.prettyln("<r><green>{d}<r><d> {s} <r>{s}<d> as {s}<r>", .{ status, @tagName(req_ctx.method), req.path, req_ctx.mime_type.value });
+ },
+ 400...499 => {
+ Output.prettyln("<r><yellow>{d}<r><d> {s} <r>{s}<d> as {s}<r>", .{ status, @tagName(req_ctx.method), req.path, req_ctx.mime_type.value });
+ },
+ else => {
+ Output.prettyln("<r><red>{d}<r><d> {s} <r>{s}<d> as {s}<r>", .{ status, @tagName(req_ctx.method), req.path, req_ctx.mime_type.value });
+ },
+ }
} else {
- println("{s} {s}", .{ @tagName(req_ctx.method), req.path });
+ switch (status) {
+ 101, 199...399 => {
+ Output.prettyln("<r><green>{d}<r><d> <r>{s}<d> {s} as {s}<r>", .{ status, @tagName(req_ctx.method), req.path, req_ctx.mime_type.value });
+ },
+ 400...499 => {
+ Output.prettyln("<r><yellow>{d}<r><d> <r>{s}<d> {s} as {s}<r>", .{ status, @tagName(req_ctx.method), req.path, req_ctx.mime_type.value });
+ },
+ else => {
+ Output.prettyln("<r><red>{d}<r><d> <r>{s}<d> {s} as {s}<r>", .{ status, @tagName(req_ctx.method), req.path, req_ctx.mime_type.value });
+ },
+ }
+
for (req_ctx.log.msgs.items) |msg| {
msg.writeFormat(Output.errorWriter()) catch continue;
}
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig
index 4d6189cbc..889da4c2e 100644
--- a/src/js_parser/js_parser.zig
+++ b/src/js_parser/js_parser.zig
@@ -1829,6 +1829,8 @@ pub const Parser = struct {
// Auto-import JSX
if (p.options.jsx.parse) {
const jsx_symbol: Symbol = p.symbols.items[p.jsx_runtime_ref.inner_index];
+ const jsx_static_symbol: Symbol = p.symbols.items[p.jsxs_runtime_ref.inner_index];
+
const jsx_fragment_symbol: Symbol = p.symbols.items[p.jsx_fragment_ref.inner_index];
const jsx_factory_symbol: Symbol = p.symbols.items[p.jsx_factory_ref.inner_index];
const jsx_filename_symbol = p.symbols.items[p.jsx_filename_ref.inner_index];
@@ -1840,7 +1842,7 @@ pub const Parser = struct {
// So a jsx_symbol usage means a jsx_factory_symbol usage
// This is kind of a broken way of doing it because it wouldn't work if it was more than one level deep
if (FeatureFlags.jsx_runtime_is_cjs) {
- if (jsx_symbol.use_count_estimate > 0) {
+ if (jsx_symbol.use_count_estimate > 0 or jsx_static_symbol.use_count_estimate > 0) {
p.recordUsage(p.jsx_automatic_ref);
}
@@ -1867,13 +1869,13 @@ pub const Parser = struct {
const automatic_namespace_ref = p.jsx_automatic_ref;
const decls_count: u32 =
- @intCast(u32, @boolToInt(jsx_symbol.use_count_estimate > 0)) +
+ @intCast(u32, @boolToInt(jsx_symbol.use_count_estimate > 0)) * 2 + @intCast(u32, @boolToInt(jsx_static_symbol.use_count_estimate > 0)) * 2 +
@intCast(u32, @boolToInt(jsx_factory_symbol.use_count_estimate > 0)) +
@intCast(u32, @boolToInt(jsx_fragment_symbol.use_count_estimate > 0)) +
@intCast(u32, @boolToInt(jsx_filename_symbol.use_count_estimate > 0));
const imports_count =
- @intCast(u32, @boolToInt(jsx_symbol.use_count_estimate > 0)) + @intCast(u32, std.math.max(jsx_factory_symbol.use_count_estimate, jsx_fragment_symbol.use_count_estimate)) + @intCast(u32, @boolToInt(p.options.features.react_fast_refresh));
+ @intCast(u32, @boolToInt(std.math.max(jsx_symbol.use_count_estimate, jsx_static_symbol.use_count_estimate) > 0)) + @intCast(u32, std.math.max(jsx_factory_symbol.use_count_estimate, jsx_fragment_symbol.use_count_estimate)) + @intCast(u32, @boolToInt(p.options.features.react_fast_refresh));
const stmts_count = imports_count + 1;
const symbols_count: u32 = imports_count + decls_count;
const loc = logger.Loc{ .start = 0 };
@@ -1892,9 +1894,7 @@ pub const Parser = struct {
var require_call_args_i: usize = 0;
var stmt_i: usize = 0;
- if (jsx_symbol.use_count_estimate > 0) {
- declared_symbols[declared_symbols_i] = .{ .ref = p.jsx_runtime_ref, .is_top_level = true };
- declared_symbols_i += 1;
+ if (jsx_symbol.use_count_estimate > 0 or jsx_static_symbol.use_count_estimate > 0) {
declared_symbols[declared_symbols_i] = .{ .ref = automatic_namespace_ref, .is_top_level = true };
declared_symbols_i += 1;
@@ -1909,24 +1909,54 @@ pub const Parser = struct {
}
};
- decls[decl_i] = G.Decl{
- .binding = p.b(
- B.Identifier{
- .ref = p.jsx_runtime_ref,
- },
- loc,
- ),
- .value = p.e(
- E.Dot{
- .target = dot_call_target,
- .name = p.options.jsx.jsx,
- .name_loc = loc,
- .can_be_removed_if_unused = true,
- },
- loc,
- ),
- };
- decl_i += 1;
+ if (jsx_symbol.use_count_estimate > 0) {
+ declared_symbols[declared_symbols_i] = .{ .ref = p.jsx_runtime_ref, .is_top_level = true };
+ declared_symbols_i += 1;
+
+ decls[decl_i] = G.Decl{
+ .binding = p.b(
+ B.Identifier{
+ .ref = p.jsx_runtime_ref,
+ },
+ loc,
+ ),
+ .value = p.e(
+ E.Dot{
+ .target = dot_call_target,
+ .name = p.options.jsx.jsx,
+ .name_loc = loc,
+ .can_be_removed_if_unused = true,
+ },
+ loc,
+ ),
+ };
+ decl_i += 1;
+ }
+
+ if (jsx_static_symbol.use_count_estimate > 0) {
+ declared_symbols[declared_symbols_i] = .{ .ref = p.jsxs_runtime_ref, .is_top_level = true };
+ declared_symbols_i += 1;
+
+ decls[decl_i] = G.Decl{
+ .binding = p.b(
+ B.Identifier{
+ .ref = p.jsxs_runtime_ref,
+ },
+ loc,
+ ),
+ .value = p.e(
+ E.Dot{
+ .target = dot_call_target,
+ .name = p.options.jsx.jsx_static,
+ .name_loc = loc,
+ .can_be_removed_if_unused = true,
+ },
+ loc,
+ ),
+ };
+
+ decl_i += 1;
+ }
if (jsx_filename_symbol.use_count_estimate > 0) {
declared_symbols[declared_symbols_i] = .{ .ref = p.jsx_filename_ref, .is_top_level = true };
@@ -2360,8 +2390,6 @@ pub const Prefill = struct {
};
pub const Runtime = struct {
pub var JSXFilename = "__jsxFilename";
- pub var JSXDevelopmentImportName = "jsxDEV";
- pub var JSXImportName = "jsx";
pub var MarkAsModule = "__markAsModule";
pub var CommonJS = "__commonJS";
pub var ReExport = "__reExport";
@@ -2540,6 +2568,7 @@ pub fn NewParser(
jsx_factory_ref: js_ast.Ref = Ref.None,
jsx_fragment_ref: js_ast.Ref = Ref.None,
jsx_automatic_ref: js_ast.Ref = Ref.None,
+ jsxs_runtime_ref: js_ast.Ref = Ref.None,
jsx_classic_ref: js_ast.Ref = Ref.None,
// only applicable when is_react_fast_refresh_enabled
@@ -3344,9 +3373,9 @@ pub fn NewParser(
if (p.options.jsx.development) {
p.jsx_filename_ref = p.newSymbol(.hoisted, Prefill.Runtime.JSXFilename) catch unreachable;
}
- const jsx_importname = p.options.jsx.jsx;
p.jsx_fragment_ref = p.declareSymbol(.hoisted, logger.Loc.Empty, p.options.jsx.fragment[p.options.jsx.fragment.len - 1]) catch unreachable;
- p.jsx_runtime_ref = p.declareSymbol(.hoisted, logger.Loc.Empty, jsx_importname) catch unreachable;
+ p.jsx_runtime_ref = p.declareSymbol(.hoisted, logger.Loc.Empty, p.options.jsx.jsx) catch unreachable;
+ p.jsxs_runtime_ref = p.declareSymbol(.hoisted, logger.Loc.Empty, p.options.jsx.jsx_static) catch unreachable;
p.jsx_factory_ref = p.declareSymbol(.hoisted, logger.Loc.Empty, p.options.jsx.factory[p.options.jsx.factory.len - 1]) catch unreachable;
if (p.options.jsx.factory.len > 1 or FeatureFlags.jsx_runtime_is_cjs) {
@@ -10484,7 +10513,7 @@ pub fn NewParser(
}
}
- const runtime = if (p.options.jsx.runtime == .automatic and !e_.flags.is_key_before_rest) options.JSX.Runtime.automatic else options.JSX.Runtime.classic;
+ const runtime = if (e_.tag != null and p.options.jsx.runtime == .automatic and !e_.flags.is_key_before_rest) options.JSX.Runtime.automatic else options.JSX.Runtime.classic;
var children_count = e_.children.len;
const is_childless_tag = FeatureFlags.react_specific_warnings and children_count > 0 and tag.data == .e_string and tag.data.e_string.isUTF8() and js_lexer.ChildlessJSXTags.has(tag.data.e_string.utf8);
@@ -10525,7 +10554,7 @@ pub fn NewParser(
// Call createElement()
return p.e(E.Call{
- .target = p.jsxStringsToMemberExpression(expr.loc, p.jsx_runtime_ref),
+ .target = p.jsxStringsToMemberExpression(expr.loc, p.jsx_factory_ref),
.args = args,
// Enable tree shaking
.can_be_unwrapped_if_unused = !p.options.ignore_dce_annotations,
@@ -10546,18 +10575,44 @@ pub fn NewParser(
// children: []
// }
- if (children_count > 0) {
- for (e_.children[0..children_count]) |child, i| {
- e_.children[i] = p.visitExpr(child);
- }
- const children_key = Expr{ .data = jsxChildrenKeyData, .loc = expr.loc };
- props.append(G.Property{
- .key = children_key,
- .value = p.e(E.Array{
- .items = e_.children,
- .is_single_line = e_.children.len < 2,
- }, expr.loc),
- }) catch unreachable;
+ const is_static_jsx = e_.children.len == 0 or e_.children.len > 1 or e_.children[0].data != .e_array;
+
+ // if (p.options.jsx.development) {
+ switch (children_count) {
+ 0 => {},
+ 1 => {
+ // static jsx must always be an array
+ if (is_static_jsx) {
+ const children_key = Expr{ .data = jsxChildrenKeyData, .loc = expr.loc };
+ e_.children[0] = p.visitExpr(e_.children[0]);
+ props.append(G.Property{
+ .key = children_key,
+ .value = p.e(E.Array{
+ .items = e_.children,
+ .is_single_line = e_.children.len < 2,
+ }, expr.loc),
+ }) catch unreachable;
+ } else {
+ const children_key = Expr{ .data = jsxChildrenKeyData, .loc = expr.loc };
+ props.append(G.Property{
+ .key = children_key,
+ .value = p.visitExpr(e_.children[0]),
+ }) catch unreachable;
+ }
+ },
+ else => {
+ for (e_.children[0..children_count]) |child, i| {
+ e_.children[i] = p.visitExpr(child);
+ }
+ const children_key = Expr{ .data = jsxChildrenKeyData, .loc = expr.loc };
+ props.append(G.Property{
+ .key = children_key,
+ .value = p.e(E.Array{
+ .items = e_.children,
+ .is_single_line = e_.children.len < 2,
+ }, expr.loc),
+ }) catch unreachable;
+ },
}
args[1] = p.e(E.Object{
@@ -10568,18 +10623,26 @@ pub fn NewParser(
args[2] = key;
} else {
// if (maybeKey !== undefined)
- args[2] = Expr{ .loc = expr.loc, .data = .{
- .e_undefined = E.Undefined{},
- } };
+ args[2] = Expr{
+ .loc = expr.loc,
+ .data = .{
+ .e_undefined = E.Undefined{},
+ },
+ };
}
if (p.options.jsx.development) {
// is the return type of the first child an array?
// It's dynamic
// Else, it's static
- args[3] = Expr{ .loc = expr.loc, .data = .{ .e_boolean = .{
- .value = e_.children.len == 0 or e_.children.len > 1 or std.meta.activeTag(e_.children[0].data) != .e_array,
- } } };
+ args[3] = Expr{
+ .loc = expr.loc,
+ .data = .{
+ .e_boolean = .{
+ .value = is_static_jsx,
+ },
+ },
+ };
var source = p.allocator.alloc(G.Property, 2) catch unreachable;
p.recordUsage(p.jsx_filename_ref);
@@ -10606,7 +10669,7 @@ pub fn NewParser(
}
return p.e(E.Call{
- .target = p.jsxStringsToMemberExpressionAutomatic(expr.loc),
+ .target = p.jsxStringsToMemberExpressionAutomatic(expr.loc, is_static_jsx),
.args = args,
// Enable tree shaking
.can_be_unwrapped_if_unused = !p.options.ignore_dce_annotations,
@@ -11696,8 +11759,8 @@ pub fn NewParser(
return false;
}
- pub fn jsxStringsToMemberExpressionAutomatic(p: *P, loc: logger.Loc) Expr {
- return p.jsxStringsToMemberExpression(loc, p.jsx_runtime_ref);
+ pub fn jsxStringsToMemberExpressionAutomatic(p: *P, loc: logger.Loc, is_static: bool) Expr {
+ return p.jsxStringsToMemberExpression(loc, if (is_static and !p.options.jsx.development) p.jsxs_runtime_ref else p.jsx_runtime_ref);
}
// If we are currently in a hoisted child of the module scope, relocate these
diff --git a/src/options.zig b/src/options.zig
index 81c01f4fd..c989e32f2 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -432,7 +432,8 @@ pub const JSX = struct {
refresh_runtime: string = "react-refresh/runtime",
supports_fast_refresh: bool = false,
- jsx: string = "jsxDEV",
+ jsx: string = Defaults.JSXFunction,
+ jsx_static: string = Defaults.JSXStaticFunction,
development: bool = true,
parse: bool = true,
@@ -465,6 +466,7 @@ pub const JSX = struct {
pub const ImportSourceDev = "react/jsx-dev-runtime";
pub const ImportSource = "react/jsx-runtime";
pub const JSXFunction = "jsx";
+ pub const JSXStaticFunction = "jsxs";
pub const JSXFunctionDev = "jsxDEV";
};
diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig
index 5a6c2f5b0..45f5c3e48 100644
--- a/src/resolver/package_json.zig
+++ b/src/resolver/package_json.zig
@@ -21,6 +21,25 @@ pub const PackageJSON = struct {
production,
};
+ const node_modules_path = std.fs.path.sep_str ++ "node_modules" ++ std.fs.path.sep_str;
+ pub fn nameForImport(this: *const PackageJSON, allocator: *std.mem.Allocator) !string {
+ if (strings.indexOf(this.source.path.text, node_modules_path)) |_| {
+ return this.name;
+ } else {
+ const parent = this.source.path.name.dirWithTrailingSlash();
+ if (strings.indexOf(parent, fs.FileSystem.instance.top_level_dir)) |i| {
+ const relative_dir = parent[i + fs.FileSystem.instance.top_level_dir.len ..];
+ var out_dir = try allocator.alloc(u8, relative_dir.len + 2);
+ std.mem.copy(u8, out_dir[2..], relative_dir);
+ out_dir[0] = '.';
+ out_dir[1] = '/';
+ return out_dir;
+ }
+
+ return this.name;
+ }
+ }
+
pub const FrameworkRouterPair = struct {
framework: *options.Framework,
router: *options.RouteConfig,
@@ -185,6 +204,7 @@ pub const PackageJSON = struct {
if (static_prop.expr.asString(allocator)) |str| {
if (str.len > 0) {
pair.router.static_dir = str;
+ pair.router.static_dir_enabled = true;
}
}
}
@@ -284,7 +304,7 @@ pub const PackageJSON = struct {
.development => {
if (framework_object.expr.asProperty("development")) |env| {
if (loadFrameworkExpression(pair.framework, env.expr, allocator, read_defines)) {
- pair.framework.package = package_json.name;
+ pair.framework.package = package_json.nameForImport(allocator) catch unreachable;
pair.framework.development = true;
if (env.expr.asProperty("static")) |static_prop| {
if (static_prop.expr.asString(allocator)) |str| {
@@ -302,7 +322,7 @@ pub const PackageJSON = struct {
.production => {
if (framework_object.expr.asProperty("production")) |env| {
if (loadFrameworkExpression(pair.framework, env.expr, allocator, read_defines)) {
- pair.framework.package = package_json.name;
+ pair.framework.package = package_json.nameForImport(allocator) catch unreachable;
pair.framework.development = false;
if (env.expr.asProperty("static")) |static_prop| {
@@ -322,7 +342,7 @@ pub const PackageJSON = struct {
}
if (loadFrameworkExpression(pair.framework, framework_object.expr, allocator, read_defines)) {
- pair.framework.package = package_json.name;
+ pair.framework.package = package_json.nameForImport(allocator) catch unreachable;
pair.framework.development = false;
}
}
diff --git a/src/runtime.version b/src/runtime.version
index fac0eba4e..dd9a0085a 100644
--- a/src/runtime.version
+++ b/src/runtime.version
@@ -1 +1 @@
-def44909172594cf \ No newline at end of file
+ef1f71fecb089b94 \ No newline at end of file
diff --git a/src/runtime/hmr.ts b/src/runtime/hmr.ts
index 99cdf634a..10f7e4a5d 100644
--- a/src/runtime/hmr.ts
+++ b/src/runtime/hmr.ts
@@ -629,6 +629,7 @@ if (typeof window !== "undefined") {
// If so, it will use it.
// Else, it will fall back to live reloading.
case API.Loader.js:
+ case API.Loader.jsx:
case API.Loader.json:
case API.Loader.ts:
case API.Loader.tsx: {