Skip to content

Commit

Permalink
Add shadcn, tailwind and react detection & templates to bun create. A…
Browse files Browse the repository at this point in the history
…lso: `bun install --analyze <files...>` (#17035)
  • Loading branch information
Jarred-Sumner authored Feb 9, 2025
1 parent 1416492 commit ba85734
Show file tree
Hide file tree
Showing 62 changed files with 4,435 additions and 280 deletions.
2 changes: 2 additions & 0 deletions docs/bundler/executables.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ import icon from "./icon.png" with { type: "file" };
import { file } from "bun";

const bytes = await file(icon).arrayBuffer();
// await fs.promises.readFile(icon)
// fs.readFileSync(icon)
```

### Embed SQLite databases
Expand Down
2 changes: 0 additions & 2 deletions docs/bundler/loaders.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,6 @@ Otherwise, the database to embed is copied into the `outdir` with a hashed filen

### `html`

**HTML loader**. Default for `.html` after Bun v1.2.0.

The html loader processes HTML files and bundles any referenced assets. It will:

- Bundle and hash referenced JavaScript files (`<script src="...">`)
Expand Down
11 changes: 6 additions & 5 deletions docs/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default {
divider("Intro"),
page("index", "What is Bun?", {
description:
"Bun is an all-in-one runtime for JavaScript and TypeScript apps. Run, bundle, and test apps with one fast tool.",
"Bun is an all-in-one runtime for JavaScript and TypeScript apps. Build, run, and test apps with one fast tool.",
}),
page("installation", "Installation", {
description: "Install Bun with npm, Homebrew, Docker, or the official install script.",
Expand Down Expand Up @@ -181,7 +181,7 @@ export default {
"Bun's package manager installs all packages into a shared global cache to avoid redundant re-downloads.",
}),
page("install/workspaces", "Workspaces", {
description: "Bun's package manager supports workspaces and mono-repo development workflows.",
description: "Bun's package manager supports workspaces and monorepo development workflows.",
}),
page("install/lifecycle", "Lifecycle scripts", {
description: "How Bun handles package lifecycle scripts with trustedDependencies",
Expand All @@ -194,7 +194,8 @@ export default {
"Bun's lockfile `bun.lock` tracks your resolved dependency tree, making future installs fast and repeatable.",
}),
page("install/registries", "Scopes and registries", {
description: "How to configure private scopes and custom package registries.",
description:
"How to configure private scopes, custom package registries, authenticating with npm token, and more.",
}),
page("install/overrides", "Overrides and resolutions", {
description: "Specify version ranges for nested dependencies",
Expand All @@ -214,8 +215,8 @@ export default {
page("bundler", "`Bun.build`", {
description: "Bundle code for consumption in the browser with Bun's native bundler.",
}),
page("bundler/html", "Frontend & static sites", {
description: `Bundle html files with Bun's native bundler.`,
page("bundler/html", "Bundle frontend & static sites", {
description: `Zero-config HTML bundler for single-page apps and multi-page apps. Automatic bundling, TailwindCSS plugins, TypeScript, JSX, React support, and incredibly fast builds`,
}),
page("bundler/fullstack", "Fullstack Dev Server", {
description: "Serve your frontend and backend from the same app with Bun's dev server.",
Expand Down
12 changes: 11 additions & 1 deletion packages/bun-types/bun.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3702,7 +3702,17 @@ declare module "bun" {
* Render contextual errors? This enables bun's error page
* @default process.env.NODE_ENV !== 'production'
*/
development?: boolean;
development?:
| boolean
| {
/**
* Enable Hot Module Replacement for routes (including React Fast Refresh, if React is in use)
*
* @default true if process.env.NODE_ENV !== 'production'
*
*/
hmr?: boolean;
};

error?: (this: Server, error: ErrorLike) => Response | Promise<Response> | undefined | Promise<undefined>;

Expand Down
51 changes: 30 additions & 21 deletions src/bake/DevServer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ pub const debug = bun.Output.Scoped(.DevServer, false);
pub const memoryLog = bun.Output.Scoped(.DevServerMemory, true);
pub const igLog = bun.Output.scoped(.IncrementalGraph, false);

/// --no-hmr sets this to false
pub var enabled = true;

pub const Options = struct {
/// Arena must live until DevServer.deinit()
arena: Allocator,
Expand Down Expand Up @@ -523,7 +520,9 @@ pub fn init(options: Options) bun.JSOOM!*DevServer {
errdefer types.deinit(allocator);

for (options.framework.file_system_router_types, 0..) |fsr, i| {
const joined_root = bun.path.joinAbs(dev.root, .auto, fsr.root);
const buf = bun.PathBufferPool.get();
defer bun.PathBufferPool.put(buf);
const joined_root = bun.path.joinAbsStringBuf(dev.root, buf, &.{fsr.root}, .auto);
const entry = dev.server_transpiler.resolver.readDirInfoIgnoreError(joined_root) orelse
continue;

Expand Down Expand Up @@ -3119,20 +3118,7 @@ pub fn IncrementalGraph(side: bake.Side) type {

// Dump to filesystem if enabled
if (bun.FeatureFlags.bake_debugging_features and content == .js) if (dev.dump_dir) |dump_dir| {
const cwd = dev.root;
var a: bun.PathBuffer = undefined;
var b: [bun.MAX_PATH_BYTES * 2]u8 = undefined;
const rel_path = bun.path.relativeBufZ(&a, cwd, key);
const size = std.mem.replacementSize(u8, rel_path, "../", "_.._/");
_ = std.mem.replace(u8, rel_path, "../", "_.._/", &b);
const rel_path_escaped = b[0..size];
dumpBundle(dump_dir, switch (side) {
.client => .client,
.server => if (is_ssr_graph) .ssr else .server,
}, rel_path_escaped, content.js, true) catch |err| {
bun.handleErrorReturnTrace(err, @errorReturnTrace());
Output.warn("Could not dump bundle: {}", .{err});
};
dumpBundleForChunk(dev, dump_dir, side, key, content.js, true, is_ssr_graph);
};

const gop = try g.bundled_files.getOrPut(dev.allocator, key);
Expand Down Expand Up @@ -4370,7 +4356,9 @@ const DirectoryWatchStore = struct {
bun.strings.startsWith(specifier, "../"))) return;
if (!std.fs.path.isAbsolute(import_source)) return;

const joined = bun.path.joinAbs(bun.path.dirname(import_source, .auto), .auto, specifier);
const buf = bun.PathBufferPool.get();
defer bun.PathBufferPool.put(buf);
const joined = bun.path.joinAbsStringBuf(bun.path.dirname(import_source, .auto), buf, &.{specifier}, .auto);
const dir = bun.path.dirname(joined, .auto);

// `import_source` is not a stable string. let's share memory with the file graph.
Expand Down Expand Up @@ -4802,7 +4790,9 @@ pub const SerializedFailure = struct {

// For debugging, it is helpful to be able to see bundles.
fn dumpBundle(dump_dir: std.fs.Dir, graph: bake.Graph, rel_path: []const u8, chunk: []const u8, wrap: bool) !void {
const name = bun.path.joinAbsString("/", &.{
const buf = bun.PathBufferPool.get();
defer bun.PathBufferPool.put(buf);
const name = bun.path.joinAbsStringBuf("/", buf, &.{
@tagName(graph),
rel_path,
}, .auto)[1..];
Expand Down Expand Up @@ -4838,6 +4828,22 @@ fn dumpBundle(dump_dir: std.fs.Dir, graph: bake.Graph, rel_path: []const u8, chu
try bufw.flush();
}

noinline fn dumpBundleForChunk(dev: *DevServer, dump_dir: std.fs.Dir, side: bake.Side, key: []const u8, code: []const u8, wrap: bool, is_ssr_graph: bool) void {
const cwd = dev.root;
var a: bun.PathBuffer = undefined;
var b: [bun.MAX_PATH_BYTES * 2]u8 = undefined;
const rel_path = bun.path.relativeBufZ(&a, cwd, key);
const size = std.mem.replacementSize(u8, rel_path, "../", "_.._/");
_ = std.mem.replace(u8, rel_path, "../", "_.._/", &b);
const rel_path_escaped = b[0..size];
dumpBundle(dump_dir, switch (side) {
.client => .client,
.server => if (is_ssr_graph) .ssr else .server,
}, rel_path_escaped, code, wrap) catch |err| {
bun.handleErrorReturnTrace(err, @errorReturnTrace());
Output.warn("Could not dump bundle: {}", .{err});
};
}
fn emitVisualizerMessageIfNeeded(dev: *DevServer) void {
if (!bun.FeatureFlags.bake_debugging_features) return;
if (dev.emit_visualizer_events == 0) return;
Expand Down Expand Up @@ -5712,7 +5718,10 @@ fn relativePath(dev: *const DevServer, path: []const u8) []const u8 {
{
return path[dev.root.len + 1 ..];
}
const rel = bun.path.relative(dev.root, path);
const relative_path_buf = &struct {
threadlocal var buf: bun.PathBuffer = undefined;
}.buf;
const rel = bun.path.relativePlatformBuf(relative_path_buf, dev.root, path, .auto, true);
// @constCast: `rel` is owned by a mutable threadlocal buffer in the path code.
bun.path.platformToPosixInPlace(u8, @constCast(rel));
return rel;
Expand Down
147 changes: 147 additions & 0 deletions src/bake/client/JavaScriptSyntaxHighlighter.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/* Dracula Syntax Highlighting Theme */
:root {
--dracula-background: #282a36;
--dracula-foreground: #f8f8f2;
--dracula-comment: #6272a4;
--dracula-cyan: #8be9fd;
--dracula-green: #50fa7b;
--dracula-orange: #ffb86c;
--dracula-pink: #ff79c6;
--dracula-purple: #bd93f9;
--dracula-red: #ff5555;
--dracula-yellow: #f1fa8c;
--dracula-selection: #44475a;
--dracula-current-line: #44475a20;
--gutter-width: 2rem;
--gutter-padding: 0.5rem;
}

pre,
code {
background-color: var(--dracula-background);
color: var(--dracula-foreground);
margin: 0;
padding: 1rem;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 14px;
line-height: 1.4;
tab-size: 2;
white-space: pre;
}

pre {
overflow-x: auto;
position: relative;
}

/* Line number support */
.dracula-theme.with-line-numbers {
counter-reset: line;
padding-left: var(--gutter-width);
}

.dracula-theme.with-line-numbers .line {
counter-increment: line;
position: relative;
vertical-align: bottom;
padding-left: var(--gutter-padding);
white-space: pre;
}

.dracula-theme.with-line-numbers .line::before {
content: counter(line);
position: absolute;
left: calc(-1 * var(--gutter-width));
width: var(--gutter-width);
height: 100%;
border-right: 1px solid var(--dracula-selection);
padding-right: var(--gutter-padding);
color: var(--dracula-comment);
text-align: right;
font-size: 12px;
user-select: none;
background-color: var(--dracula-background);
font-variant-numeric: tabular-nums;
}

.dracula-theme.with-line-numbers .line:hover {
background-color: var(--dracula-current-line);
}

/* Token classes mapped to Dracula spec */
.syntax-pink {
color: var(--dracula-pink);
}

.syntax-cyan {
color: var(--dracula-cyan);
}

.syntax-orange {
color: var(--dracula-orange);
}

.syntax-red {
color: var(--dracula-red);
}

.syntax-green {
color: var(--dracula-green);
}

.syntax-yellow {
color: var(--dracula-yellow);
}

.syntax-gray {
color: var(--dracula-comment);
}

.syntax-purple {
color: var(--dracula-purple);
}

.syntax-fg {
color: var(--dracula-foreground);
}

/* Style modifiers */
.italic {
font-style: italic;
}

.bold {
font-weight: bold;
}

/* Combined token classes */
.syntax-cyan.italic {
color: var(--dracula-cyan);
font-style: italic;
}

.syntax-orange.italic {
color: var(--dracula-orange);
font-style: italic;
}

.syntax-green.italic {
color: var(--dracula-green);
font-style: italic;
}

.syntax-pink.bold {
color: var(--dracula-pink);
font-weight: bold;
}

/* Template literals and interpolation */
.syntax-yellow .interpolation {
color: var(--dracula-pink);
}

/* Ensure proper contrast on selection */
::selection {
background-color: var(--dracula-selection);
color: var(--dracula-foreground);
}
Loading

0 comments on commit ba85734

Please # to comment.