mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
4
.gitignore
vendored
4
.gitignore
vendored
@@ -39,4 +39,6 @@ out
|
||||
esbuilddir
|
||||
*.jsb
|
||||
parceldist
|
||||
esbuilddir
|
||||
esbuilddir
|
||||
outdir/
|
||||
outcss
|
||||
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -17,7 +17,12 @@
|
||||
"request": "launch",
|
||||
"name": "Dev Launch",
|
||||
"program": "${workspaceFolder}/build/debug/macos-x86_64/esdev",
|
||||
"args": ["optional-chain-polyfill.js", "--resolve=disable"],
|
||||
"args": [
|
||||
"./simple.css",
|
||||
"--resolve=dev",
|
||||
"--outdir=outcss",
|
||||
"--public-url=https://localhost:9000/"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/src/test/fixtures",
|
||||
"console": "internalConsole"
|
||||
},
|
||||
|
||||
16
build.zig
16
build.zig
@@ -4,7 +4,7 @@ const resolve_path = @import("./src/resolver/resolve_path.zig");
|
||||
pub fn addPicoHTTP(step: *std.build.LibExeObjStep, dir: []const u8) void {
|
||||
const picohttp = step.addPackage(.{
|
||||
.name = "picohttp",
|
||||
.path = "src/deps/picohttp.zig",
|
||||
.path = .{ .path = "src/deps/picohttp.zig" },
|
||||
});
|
||||
|
||||
step.addObjectFile(
|
||||
@@ -35,7 +35,7 @@ pub fn build(b: *std.build.Builder) void {
|
||||
if (target.getOsTag() == .wasi) {
|
||||
exe.enable_wasmtime = true;
|
||||
exe = b.addExecutable("esdev", "src/main_wasi.zig");
|
||||
exe.is_dynamic = true;
|
||||
exe.linkage = .dynamic;
|
||||
exe.setOutputDir(output_dir);
|
||||
} else if (target.getCpuArch().isWasm()) {
|
||||
// exe = b.addExecutable(
|
||||
@@ -60,15 +60,15 @@ pub fn build(b: *std.build.Builder) void {
|
||||
|
||||
lib.setOutputDir(output_dir);
|
||||
lib.want_lto = true;
|
||||
b.install_path = lib.getOutputPath();
|
||||
b.install_path = lib.getOutputSource().getPath(b);
|
||||
|
||||
std.debug.print("Build: ./{s}\n", .{lib.getOutputPath()});
|
||||
std.debug.print("Build: ./{s}\n", .{b.install_path});
|
||||
b.default_step.dependOn(&lib.step);
|
||||
b.verbose_link = true;
|
||||
lib.setTarget(target);
|
||||
lib.setBuildMode(mode);
|
||||
|
||||
std.fs.deleteTreeAbsolute(std.fs.path.join(std.heap.page_allocator, &.{ cwd, lib.getOutputPath() }) catch unreachable) catch {};
|
||||
std.fs.deleteTreeAbsolute(std.fs.path.join(std.heap.page_allocator, &.{ cwd, lib.getOutputSource().getPath(b) }) catch unreachable) catch {};
|
||||
var install = b.getInstallStep();
|
||||
lib.strip = false;
|
||||
lib.install();
|
||||
@@ -92,11 +92,11 @@ pub fn build(b: *std.build.Builder) void {
|
||||
|
||||
exe.addPackage(.{
|
||||
.name = "clap",
|
||||
.path = "src/deps/zig-clap/clap.zig",
|
||||
.path = .{ .path = "src/deps/zig-clap/clap.zig" },
|
||||
});
|
||||
|
||||
exe.setOutputDir(output_dir);
|
||||
std.debug.print("Build: ./{s}\n", .{exe.getOutputPath()});
|
||||
|
||||
var walker = std.fs.walkPath(std.heap.page_allocator, cwd) catch unreachable;
|
||||
if (std.builtin.is_test) {
|
||||
while (walker.next() catch unreachable) |entry| {
|
||||
@@ -141,4 +141,6 @@ pub fn build(b: *std.build.Builder) void {
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
||||
std.debug.print("Build: ./{s}/{s}\n", .{ output_dir, "esdev" });
|
||||
}
|
||||
|
||||
113
outdir/index.css
113
outdir/index.css
@@ -1,113 +0,0 @@
|
||||
/* src/api/demo/styles/Home.module.css */
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
padding: 0 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
.main {
|
||||
padding: 5rem 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.footer {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
border-top: 1px solid #eaeaea;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.footer a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.title a {
|
||||
color: #0070f3;
|
||||
text-decoration: none;
|
||||
}
|
||||
.title a:hover,
|
||||
.title a:focus,
|
||||
.title a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.title {
|
||||
margin: 0;
|
||||
line-height: 1.15;
|
||||
font-size: 4rem;
|
||||
}
|
||||
.title,
|
||||
.description {
|
||||
text-align: center;
|
||||
}
|
||||
.description {
|
||||
line-height: 1.5;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.code {
|
||||
background: #fafafa;
|
||||
border-radius: 5px;
|
||||
padding: 0.75rem;
|
||||
font-size: 1.1rem;
|
||||
font-family:
|
||||
Menlo,
|
||||
Monaco,
|
||||
Lucida Console,
|
||||
Liberation Mono,
|
||||
DejaVu Sans Mono,
|
||||
Bitstream Vera Sans Mono,
|
||||
Courier New,
|
||||
monospace;
|
||||
}
|
||||
.grid {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
max-width: 800px;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
.card {
|
||||
margin: 1rem;
|
||||
padding: 1.5rem;
|
||||
text-align: left;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
border: 1px solid #eaeaea;
|
||||
border-radius: 10px;
|
||||
transition: color 0.15s ease, border-color 0.15s ease;
|
||||
width: 45%;
|
||||
}
|
||||
.card:hover,
|
||||
.card:focus,
|
||||
.card:active {
|
||||
color: #0070f3;
|
||||
border-color: #0070f3;
|
||||
}
|
||||
.card h2 {
|
||||
margin: 0 0 1rem 0;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.card p {
|
||||
margin: 0;
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.logo {
|
||||
height: 1em;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.grid {
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
2338
outdir/index.js
2338
outdir/index.js
File diff suppressed because it is too large
Load Diff
@@ -151,7 +151,7 @@ pub fn NewBundler(cache_files: bool) type {
|
||||
linker: Linker,
|
||||
timer: Timer = Timer{},
|
||||
|
||||
pub const RuntimeCode = @embedFile("./runtime.js");
|
||||
pub const isCacheEnabled = cache_files;
|
||||
|
||||
// to_bundle:
|
||||
|
||||
@@ -949,9 +949,30 @@ pub fn NewBundler(cache_files: bool) type {
|
||||
js_printer.FileWriter,
|
||||
js_printer.NewFileWriter(file),
|
||||
);
|
||||
|
||||
var file_op = options.OutputFile.FileOperation.fromFile(file.handle, file_path.pretty);
|
||||
|
||||
file_op.fd = file.handle;
|
||||
|
||||
file_op.is_tmpdir = false;
|
||||
|
||||
if (Outstream == std.fs.Dir) {
|
||||
file_op.dir = outstream.fd;
|
||||
|
||||
if (bundler.fs.fs.needToCloseFiles()) {
|
||||
file.close();
|
||||
file_op.fd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
output_file.value = .{ .move = file_op };
|
||||
},
|
||||
.css => {
|
||||
const CSSWriter = Css.NewWriter(@TypeOf(file), @TypeOf(bundler.linker), import_path_format);
|
||||
const CSSWriter = Css.NewWriter(
|
||||
std.fs.File,
|
||||
@TypeOf(&bundler.linker),
|
||||
import_path_format,
|
||||
);
|
||||
const entry = bundler.resolver.caches.fs.readFile(
|
||||
bundler.fs,
|
||||
file_path.text,
|
||||
@@ -963,27 +984,48 @@ pub fn NewBundler(cache_files: bool) type {
|
||||
const _file = Fs.File{ .path = file_path, .contents = entry.contents };
|
||||
const source = try logger.Source.initFile(_file, bundler.allocator);
|
||||
|
||||
var css_writer = CSSWriter.init(&source, file, bundler.linker);
|
||||
var css_writer = CSSWriter.init(
|
||||
&source,
|
||||
file,
|
||||
&bundler.linker,
|
||||
);
|
||||
try css_writer.run(bundler.log, bundler.allocator);
|
||||
output_file.size = css_writer.written;
|
||||
var file_op = options.OutputFile.FileOperation.fromFile(file.handle, file_path.pretty);
|
||||
|
||||
file_op.fd = file.handle;
|
||||
|
||||
file_op.is_tmpdir = false;
|
||||
|
||||
if (Outstream == std.fs.Dir) {
|
||||
file_op.dir = outstream.fd;
|
||||
|
||||
if (bundler.fs.fs.needToCloseFiles()) {
|
||||
file.close();
|
||||
file_op.fd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
output_file.value = .{ .move = file_op };
|
||||
},
|
||||
// TODO:
|
||||
else => {},
|
||||
}
|
||||
.file => {
|
||||
var hashed_name = try bundler.linker.getHashedFilename(file_path, null);
|
||||
var pathname = try bundler.allocator.alloc(u8, hashed_name.len + file_path.name.ext.len);
|
||||
std.mem.copy(u8, pathname, hashed_name);
|
||||
std.mem.copy(u8, pathname[hashed_name.len..], file_path.name.ext);
|
||||
const dir = if (bundler.options.output_dir_handle) |output_handle| output_handle.fd else 0;
|
||||
|
||||
var file_op = options.OutputFile.FileOperation.fromFile(file.handle, file_path.pretty);
|
||||
output_file.value = .{
|
||||
.copy = options.OutputFile.FileOperation{
|
||||
.pathname = pathname,
|
||||
.dir = dir,
|
||||
.is_outdir = true,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
file_op.fd = file.handle;
|
||||
|
||||
file_op.is_tmpdir = false;
|
||||
output_file.value = .{ .move = file_op };
|
||||
if (Outstream == std.fs.Dir) {
|
||||
file_op.dir = outstream.fd;
|
||||
|
||||
if (bundler.fs.fs.needToCloseFiles()) {
|
||||
file.close();
|
||||
file_op.fd = 0;
|
||||
}
|
||||
// // TODO:
|
||||
// else => {},
|
||||
}
|
||||
|
||||
return output_file;
|
||||
|
||||
10
src/cli.zig
10
src/cli.zig
@@ -457,15 +457,7 @@ pub const Cli = struct {
|
||||
// try f.moveTo(result.outbase, constStrToU8(rel_path), root_dir.fd);
|
||||
},
|
||||
.copy => |value| {
|
||||
const rel_path_base = resolve_path.relativeToCommonPath(
|
||||
from_path,
|
||||
from_path,
|
||||
f.input.text,
|
||||
filepath_buf[2..],
|
||||
comptime resolve_path.Platform.auto.separator(),
|
||||
false,
|
||||
);
|
||||
rel_path = filepath_buf[0 .. rel_path_base.len + 2];
|
||||
rel_path = value.pathname;
|
||||
|
||||
try f.copyTo(result.outbase, constStrToU8(rel_path), root_dir.fd);
|
||||
},
|
||||
|
||||
1038
src/css_scanner.zig
1038
src/css_scanner.zig
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
pub usingnamespace @import("std").c.builtins;
|
||||
usingnamespace @import("std").c;
|
||||
|
||||
// int clonefileat(int src_dirfd, const char * src, int dst_dirfd, const char * dst, int flags);
|
||||
pub extern "c" fn clonefileat(c_int, [*c]const u8, c_int, [*c]const u8, uint32_t: c_int) c_int;
|
||||
@@ -11,5 +11,3 @@ pub extern "c" fn chmod([*c]const u8, mode_t) c_int;
|
||||
pub extern "c" fn fchmod(c_int, mode_t) c_int;
|
||||
pub extern "c" fn umask(mode_t) mode_t;
|
||||
pub extern "c" fn fchmodat(c_int, [*c]const u8, mode_t, c_int) c_int;
|
||||
|
||||
const mode_t = u16;
|
||||
|
||||
21
src/env.zig
Normal file
21
src/env.zig
Normal file
@@ -0,0 +1,21 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub const BuildTarget = enum { native, wasm, wasi };
|
||||
pub const build_target: BuildTarget = {
|
||||
if (std.Target.current.isWasm() and std.Target.current.getOsTag() == .wasi) {
|
||||
return BuildTarget.wasi;
|
||||
} else if (std.Target.current.isWasm()) {
|
||||
return BuildTarget.wasm;
|
||||
} else {
|
||||
return BuildTarget.native;
|
||||
}
|
||||
};
|
||||
|
||||
pub const isWasm = build_target == .wasm;
|
||||
pub const isNative = build_target == .native;
|
||||
pub const isWasi = build_target == .wasi;
|
||||
pub const isMac = build_target == .native and std.Target.current.os.tag == .macos;
|
||||
pub const isBrowser = !isWasi and isWasm;
|
||||
pub const isWindows = std.Target.current.os.tag == .windows;
|
||||
pub const isDebug = std.builtin.Mode.Debug == std.builtin.mode;
|
||||
pub const isTest = std.builtin.is_test;
|
||||
36
src/feature_flags.zig
Normal file
36
src/feature_flags.zig
Normal file
@@ -0,0 +1,36 @@
|
||||
const env = @import("env.zig");
|
||||
|
||||
pub const strong_etags_for_built_files = true;
|
||||
pub const keep_alive = true;
|
||||
|
||||
// it just doesn't work well.
|
||||
pub const use_std_path_relative = false;
|
||||
pub const use_std_path_join = false;
|
||||
|
||||
// Debug helpers
|
||||
pub const print_ast = false;
|
||||
pub const disable_printing_null = false;
|
||||
|
||||
// This was a ~5% performance improvement
|
||||
pub const store_file_descriptors = !env.isWindows and !env.isBrowser;
|
||||
|
||||
// This doesn't really seem to do anything for us
|
||||
pub const disable_filesystem_cache = false and std.Target.current.os.tag == .macos;
|
||||
|
||||
pub const css_in_js_import_behavior = CSSModulePolyfill.facade;
|
||||
|
||||
pub const only_output_esm = true;
|
||||
|
||||
pub const jsx_runtime_is_cjs = true;
|
||||
|
||||
pub const bundle_node_modules = true;
|
||||
|
||||
pub const tracing = true;
|
||||
|
||||
pub const verbose_watcher = true;
|
||||
|
||||
pub const CSSModulePolyfill = enum {
|
||||
// When you import a .css file and you reference the import in JavaScript
|
||||
// Just return whatever the property key they referenced was
|
||||
facade,
|
||||
};
|
||||
28
src/fs.zig
28
src/fs.zig
@@ -462,6 +462,34 @@ pub const FileSystem = struct {
|
||||
mtime: i128 = 0,
|
||||
mode: std.fs.File.Mode = 0,
|
||||
|
||||
threadlocal var hash_bytes: [32]u8 = undefined;
|
||||
threadlocal var hash_name_buf: [1024]u8 = undefined;
|
||||
|
||||
pub fn hashName(
|
||||
this: *const ModKey,
|
||||
basename: string,
|
||||
) !string {
|
||||
|
||||
// We shouldn't just read the contents of the ModKey into memory
|
||||
// The hash should be deterministic across computers and operating systems.
|
||||
// inode is non-deterministic across volumes within the same compuiter
|
||||
// so if we're not going to do a full content hash, we should use mtime and size.
|
||||
// even mtime is debatable.
|
||||
var hash_bytes_remain: []u8 = hash_bytes[0..];
|
||||
std.mem.writeIntNative(@TypeOf(this.size), hash_bytes_remain[0..@sizeOf(@TypeOf(this.size))], this.size);
|
||||
hash_bytes_remain = hash_bytes_remain[@sizeOf(@TypeOf(this.size))..];
|
||||
std.mem.writeIntNative(@TypeOf(this.mtime), hash_bytes_remain[0..@sizeOf(@TypeOf(this.mtime))], this.mtime);
|
||||
|
||||
return try std.fmt.bufPrint(
|
||||
&hash_name_buf,
|
||||
"{s}-{x}",
|
||||
.{
|
||||
basename,
|
||||
@truncate(u32, std.hash.Wyhash.hash(1, &hash_bytes)),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn generate(fs: *RealFS, path: string, file: std.fs.File) anyerror!ModKey {
|
||||
const stat = try file.stat();
|
||||
|
||||
|
||||
@@ -2,63 +2,9 @@ const std = @import("std");
|
||||
pub usingnamespace @import("strings.zig");
|
||||
|
||||
pub const C = @import("c.zig");
|
||||
pub const BuildTarget = enum { native, wasm, wasi };
|
||||
pub const build_target: BuildTarget = comptime {
|
||||
if (std.Target.current.isWasm() and std.Target.current.getOsTag() == .wasi) {
|
||||
return BuildTarget.wasi;
|
||||
} else if (std.Target.current.isWasm()) {
|
||||
return BuildTarget.wasm;
|
||||
} else {
|
||||
return BuildTarget.native;
|
||||
}
|
||||
};
|
||||
pub usingnamespace @import("env.zig");
|
||||
|
||||
pub const isWasm = build_target == .wasm;
|
||||
pub const isNative = build_target == .native;
|
||||
pub const isWasi = build_target == .wasi;
|
||||
pub const isMac = build_target == .native and std.Target.current.os.tag == .macos;
|
||||
pub const isBrowser = !isWasi and isWasm;
|
||||
pub const isWindows = std.Target.current.os.tag == .windows;
|
||||
|
||||
pub const FeatureFlags = struct {
|
||||
pub const strong_etags_for_built_files = true;
|
||||
pub const keep_alive = true;
|
||||
|
||||
// it just doesn't work well.
|
||||
pub const use_std_path_relative = false;
|
||||
pub const use_std_path_join = false;
|
||||
|
||||
// Debug helpers
|
||||
pub const print_ast = false;
|
||||
pub const disable_printing_null = false;
|
||||
|
||||
// This was a ~5% performance improvement
|
||||
pub const store_file_descriptors = !isWindows and !isBrowser;
|
||||
|
||||
// This doesn't really seem to do anything for us
|
||||
pub const disable_filesystem_cache = false and std.Target.current.os.tag == .macos;
|
||||
|
||||
pub const css_in_js_import_behavior = CSSModulePolyfill.facade;
|
||||
|
||||
pub const only_output_esm = true;
|
||||
|
||||
pub const jsx_runtime_is_cjs = true;
|
||||
|
||||
pub const bundle_node_modules = true;
|
||||
|
||||
pub const tracing = true;
|
||||
|
||||
pub const verbose_watcher = true;
|
||||
|
||||
pub const CSSModulePolyfill = enum {
|
||||
// When you import a .css file and you reference the import in JavaScript
|
||||
// Just return whatever the property key they referenced was
|
||||
facade,
|
||||
};
|
||||
};
|
||||
|
||||
pub const isDebug = std.builtin.Mode.Debug == std.builtin.mode;
|
||||
pub const isTest = std.builtin.is_test;
|
||||
pub const FeatureFlags = @import("feature_flags.zig");
|
||||
|
||||
pub const Output = struct {
|
||||
threadlocal var source: *Source = undefined;
|
||||
|
||||
@@ -237,7 +237,7 @@ pub const RequestContext = struct {
|
||||
ctx.appendHeader("Transfer-Encoding", "Chunked");
|
||||
} else {
|
||||
const length_str = try ctx.allocator.alloc(u8, 64);
|
||||
ctx.appendHeader("Content-Length", length_str[0..std.fmt.formatIntBuf(length_str, length, 10, true, .{})]);
|
||||
ctx.appendHeader("Content-Length", length_str[0..std.fmt.formatIntBuf(length_str, length, 10, .upper, .{})]);
|
||||
}
|
||||
|
||||
try ctx.flushHeaders();
|
||||
@@ -952,7 +952,7 @@ pub const RequestContext = struct {
|
||||
if (FeatureFlags.strong_etags_for_built_files) {
|
||||
if (buf.len < 16 * 16 * 16 * 16) {
|
||||
const strong_etag = std.hash.Wyhash.hash(1, buf);
|
||||
const etag_content_slice = std.fmt.bufPrintIntToSlice(strong_etag_buffer[0..49], strong_etag, 16, true, .{});
|
||||
const etag_content_slice = std.fmt.bufPrintIntToSlice(strong_etag_buffer[0..49], strong_etag, 16, .upper, .{});
|
||||
|
||||
chunky.rctx.appendHeader("ETag", etag_content_slice);
|
||||
|
||||
@@ -1047,7 +1047,7 @@ pub const RequestContext = struct {
|
||||
weak_etag.update(weak_etag_tmp_buffer[0..16]);
|
||||
}
|
||||
|
||||
const etag_content_slice = std.fmt.bufPrintIntToSlice(weak_etag_buffer[2..], weak_etag.final(), 16, true, .{});
|
||||
const etag_content_slice = std.fmt.bufPrintIntToSlice(weak_etag_buffer[2..], weak_etag.final(), 16, .upper, .{});
|
||||
const complete_weak_etag = weak_etag_buffer[0 .. etag_content_slice.len + 2];
|
||||
|
||||
ctx.appendHeader("ETag", complete_weak_etag);
|
||||
@@ -1101,7 +1101,7 @@ pub const RequestContext = struct {
|
||||
if (FeatureFlags.strong_etags_for_built_files) {
|
||||
// TODO: don't hash runtime.js
|
||||
const strong_etag = std.hash.Wyhash.hash(1, buffer);
|
||||
const etag_content_slice = std.fmt.bufPrintIntToSlice(strong_etag_buffer[0..49], strong_etag, 16, true, .{});
|
||||
const etag_content_slice = std.fmt.bufPrintIntToSlice(strong_etag_buffer[0..49], strong_etag, 16, .upper, .{});
|
||||
|
||||
ctx.appendHeader("ETag", etag_content_slice);
|
||||
|
||||
|
||||
@@ -482,7 +482,7 @@ pub fn NewPrinter(
|
||||
// In JavaScript, numbers are represented as 64 bit floats
|
||||
// However, they could also be signed or unsigned int 32 (when doing bit shifts)
|
||||
// In this case, it's always going to unsigned since that conversion has already happened.
|
||||
std.fmt.formatInt(@floatToInt(u32, float), 10, true, .{}, p) catch unreachable;
|
||||
std.fmt.formatInt(@floatToInt(u32, float), 10, .upper, .{}, p) catch unreachable;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3274,7 +3274,7 @@ pub fn NewPrinter(
|
||||
pub fn printLoadFromBundleWithoutCall(p: *Printer, import_record_index: u32) void {
|
||||
const record = p.import_records[import_record_index];
|
||||
p.print("$");
|
||||
std.fmt.formatInt(record.module_id, 16, false, .{}, p) catch unreachable;
|
||||
std.fmt.formatInt(record.module_id, 16, .lower, .{}, p) catch unreachable;
|
||||
}
|
||||
pub fn printBundledRequire(p: *Printer, require: E.Require) void {
|
||||
if (p.import_records[require.import_record_index].is_internal) {
|
||||
@@ -3426,7 +3426,7 @@ pub fn NewPrinter(
|
||||
p.print("// ");
|
||||
p.print(p.options.source_path.?.pretty);
|
||||
p.print("\nexport var $");
|
||||
std.fmt.formatInt(p.options.module_hash, 16, false, .{}, p) catch unreachable;
|
||||
std.fmt.formatInt(p.options.module_hash, 16, .lower, .{}, p) catch unreachable;
|
||||
p.print(" = ");
|
||||
p.printExpr(decls[0].value.?, .comma, ExprFlag.None());
|
||||
p.printSemicolonAfterStatement();
|
||||
|
||||
167
src/linker.zig
167
src/linker.zig
@@ -28,8 +28,11 @@ const Bundler = _bundler.Bundler;
|
||||
const ResolveQueue = _bundler.ResolveQueue;
|
||||
const Runtime = @import("./runtime.zig").Runtime;
|
||||
|
||||
pub const CSSResolveError = error{ResolveError};
|
||||
|
||||
pub fn NewLinker(comptime BundlerType: type) type {
|
||||
return struct {
|
||||
const HashedFileNameMap = std.AutoHashMap(u64, string);
|
||||
const ThisLinker = @This();
|
||||
allocator: *std.mem.Allocator,
|
||||
options: *Options.BundleOptions,
|
||||
@@ -41,6 +44,7 @@ pub fn NewLinker(comptime BundlerType: type) type {
|
||||
any_needs_runtime: bool = false,
|
||||
runtime_import_record: ?ImportRecord = null,
|
||||
runtime_source_path: string,
|
||||
hashed_filenames: HashedFileNameMap,
|
||||
|
||||
pub fn init(
|
||||
allocator: *std.mem.Allocator,
|
||||
@@ -62,6 +66,7 @@ pub fn NewLinker(comptime BundlerType: type) type {
|
||||
.resolver = resolver,
|
||||
.resolve_results = resolve_results,
|
||||
.runtime_source_path = fs.absAlloc(allocator, &([_]string{"__runtime.js"})) catch unreachable,
|
||||
.hashed_filenames = HashedFileNameMap.init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -71,35 +76,87 @@ pub fn NewLinker(comptime BundlerType: type) type {
|
||||
return RequireOrImportMeta{};
|
||||
}
|
||||
|
||||
pub fn resolveCSS(
|
||||
pub fn getHashedFilename(
|
||||
this: *ThisLinker,
|
||||
file_path: Fs.Path,
|
||||
fd: ?FileDescriptorType,
|
||||
) !string {
|
||||
if (BundlerType.isCacheEnabled) {
|
||||
var hashed = std.hash.Wyhash.hash(0, file_path.text);
|
||||
var hashed_result = try this.hashed_filenames.getOrPut(hashed);
|
||||
if (hashed_result.found_existing) {
|
||||
return hashed_result.value_ptr.*;
|
||||
}
|
||||
}
|
||||
|
||||
var file: std.fs.File = if (fd) |_fd| std.fs.File{ .handle = _fd } else try std.fs.openFileAbsolute(file_path.text, .{ .read = true });
|
||||
Fs.FileSystem.setMaxFd(file.handle);
|
||||
var modkey = try Fs.FileSystem.RealFS.ModKey.generate(&this.fs.fs, file_path.text, file);
|
||||
const hash_name = try modkey.hashName(file_path.name.base);
|
||||
|
||||
if (BundlerType.isCacheEnabled) {
|
||||
var hashed = std.hash.Wyhash.hash(0, file_path.text);
|
||||
try this.hashed_filenames.put(hashed, try this.allocator.dupe(u8, hash_name));
|
||||
}
|
||||
|
||||
if (this.fs.fs.needToCloseFiles() and fd == null) {
|
||||
file.close();
|
||||
}
|
||||
|
||||
return hash_name;
|
||||
}
|
||||
|
||||
pub fn resolveCSS(
|
||||
this: anytype,
|
||||
path: Fs.Path,
|
||||
url: string,
|
||||
range: logger.Range,
|
||||
comptime kind: ImportKind,
|
||||
kind: ImportKind,
|
||||
comptime import_path_format: Options.BundleOptions.ImportPathFormat,
|
||||
) !string {
|
||||
const dir = path.name.dirWithTrailingSlash();
|
||||
|
||||
switch (kind) {
|
||||
.at => {
|
||||
var resolve_result = try this.resolver.resolve(path.name.dir, url, .at);
|
||||
var resolve_result = try this.resolver.resolve(dir, url, .at);
|
||||
if (resolve_result.is_external) {
|
||||
return resolve_result.path_pair.primary.text;
|
||||
}
|
||||
|
||||
var import_record = ImportRecord{ .range = range, .path = resolve_result.path_pair.primary, .kind = kind };
|
||||
try this.processImportRecord(path.name.dir, &resolve_result, &import_record, import_path_format);
|
||||
|
||||
const loader = this.options.loaders.get(resolve_result.path_pair.primary.name.ext) orelse .file;
|
||||
|
||||
this.processImportRecord(loader, dir, &resolve_result, &import_record, import_path_format) catch unreachable;
|
||||
return import_record.path.text;
|
||||
},
|
||||
.at_conditional => {
|
||||
var resolve_result = try this.resolver.resolve(path.name.dir, url, .at_conditional);
|
||||
var resolve_result = try this.resolver.resolve(dir, url, .at_conditional);
|
||||
if (resolve_result.is_external) {
|
||||
return resolve_result.path_pair.primary.text;
|
||||
}
|
||||
|
||||
var import_record = ImportRecord{ .range = range, .path = resolve_result.path_pair.primary, .kind = kind };
|
||||
try this.processImportRecord(path.name.dir, &resolve_result, &import_record, import_path_format);
|
||||
const loader = this.options.loaders.get(resolve_result.path_pair.primary.name.ext) orelse .file;
|
||||
|
||||
this.processImportRecord(loader, dir, &resolve_result, &import_record, import_path_format) catch unreachable;
|
||||
return import_record.path.text;
|
||||
},
|
||||
.url => {
|
||||
var resolve_result = try this.resolver.resolve(path.name.dir, url, .url);
|
||||
var resolve_result = try this.resolver.resolve(dir, url, .url);
|
||||
if (resolve_result.is_external) {
|
||||
return resolve_result.path_pair.primary.text;
|
||||
}
|
||||
|
||||
var import_record = ImportRecord{ .range = range, .path = resolve_result.path_pair.primary, .kind = kind };
|
||||
try this.processImportRecord(path.name.dir, &resolve_result, &import_record, import_path_format);
|
||||
const loader = this.options.loaders.get(resolve_result.path_pair.primary.name.ext) orelse .file;
|
||||
|
||||
this.processImportRecord(loader, dir, &resolve_result, &import_record, import_path_format) catch unreachable;
|
||||
return import_record.path.text;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
// pub const Scratch = struct {
|
||||
@@ -137,6 +194,7 @@ pub fn NewLinker(comptime BundlerType: type) type {
|
||||
source_dir,
|
||||
linker.runtime_source_path,
|
||||
Runtime.version(),
|
||||
false,
|
||||
import_path_format,
|
||||
);
|
||||
result.ast.runtime_import_record_id = record_index;
|
||||
@@ -214,6 +272,8 @@ pub fn NewLinker(comptime BundlerType: type) type {
|
||||
}
|
||||
|
||||
linker.processImportRecord(
|
||||
linker.options.loaders.get(resolved_import.path_pair.primary.name.ext) orelse .file,
|
||||
|
||||
// Include trailing slash
|
||||
file_path.text[0 .. source_dir.len + 1],
|
||||
resolved_import,
|
||||
@@ -290,6 +350,7 @@ pub fn NewLinker(comptime BundlerType: type) type {
|
||||
source_dir,
|
||||
linker.runtime_source_path,
|
||||
Runtime.version(),
|
||||
false,
|
||||
import_path_format,
|
||||
),
|
||||
.range = logger.Range{ .loc = logger.Loc{ .start = 0 }, .len = 0 },
|
||||
@@ -355,18 +416,54 @@ pub fn NewLinker(comptime BundlerType: type) type {
|
||||
source_dir: string,
|
||||
source_path: string,
|
||||
package_version: ?string,
|
||||
use_hashed_name: bool,
|
||||
comptime import_path_format: Options.BundleOptions.ImportPathFormat,
|
||||
) !Fs.Path {
|
||||
switch (import_path_format) {
|
||||
.relative => {
|
||||
var pretty = try linker.allocator.dupe(u8, linker.fs.relative(source_dir, source_path));
|
||||
var pathname = Fs.PathName.init(pretty);
|
||||
return Fs.Path.initWithPretty(pretty, pretty);
|
||||
var relative_name = linker.fs.relative(source_dir, source_path);
|
||||
var pretty: string = undefined;
|
||||
if (use_hashed_name) {
|
||||
var basepath = Fs.Path.init(source_path);
|
||||
const basename = try linker.getHashedFilename(basepath, null);
|
||||
var dir = basepath.name.dirWithTrailingSlash();
|
||||
var _pretty = try linker.allocator.alloc(u8, dir.len + basename.len + basepath.name.ext.len);
|
||||
std.mem.copy(u8, _pretty, dir);
|
||||
var remaining_pretty = _pretty[dir.len..];
|
||||
std.mem.copy(u8, remaining_pretty, basename);
|
||||
remaining_pretty = remaining_pretty[basename.len..];
|
||||
std.mem.copy(u8, remaining_pretty, basepath.name.ext);
|
||||
pretty = _pretty;
|
||||
relative_name = try linker.allocator.dupe(u8, relative_name);
|
||||
} else {
|
||||
pretty = try linker.allocator.dupe(u8, relative_name);
|
||||
relative_name = pretty;
|
||||
}
|
||||
|
||||
return Fs.Path.initWithPretty(pretty, relative_name);
|
||||
},
|
||||
.relative_nodejs => {
|
||||
var pretty = try linker.allocator.dupe(u8, linker.fs.relative(source_dir, source_path));
|
||||
var relative_name = linker.fs.relative(source_dir, source_path);
|
||||
var pretty: string = undefined;
|
||||
if (use_hashed_name) {
|
||||
var basepath = Fs.Path.init(source_path);
|
||||
const basename = try linker.getHashedFilename(basepath, null);
|
||||
var dir = basepath.name.dirWithTrailingSlash();
|
||||
var _pretty = try linker.allocator.alloc(u8, dir.len + basename.len + basepath.name.ext.len);
|
||||
std.mem.copy(u8, _pretty, dir);
|
||||
var remaining_pretty = _pretty[dir.len..];
|
||||
std.mem.copy(u8, remaining_pretty, basename);
|
||||
remaining_pretty = remaining_pretty[basename.len..];
|
||||
std.mem.copy(u8, remaining_pretty, basepath.name.ext);
|
||||
pretty = _pretty;
|
||||
relative_name = try linker.allocator.dupe(u8, relative_name);
|
||||
} else {
|
||||
pretty = try linker.allocator.dupe(u8, relative_name);
|
||||
relative_name = pretty;
|
||||
}
|
||||
|
||||
var pathname = Fs.PathName.init(pretty);
|
||||
var path = Fs.Path.initWithPretty(pretty, pretty);
|
||||
var path = Fs.Path.initWithPretty(pretty, relative_name);
|
||||
path.text = path.text[0 .. path.text.len - path.name.ext.len];
|
||||
return path;
|
||||
},
|
||||
@@ -385,33 +482,27 @@ pub fn NewLinker(comptime BundlerType: type) type {
|
||||
base = base[0..dot];
|
||||
}
|
||||
|
||||
if (linker.options.append_package_version_in_query_string and package_version != null) {
|
||||
const absolute_url =
|
||||
try std.fmt.allocPrint(
|
||||
linker.allocator,
|
||||
"{s}{s}{s}?v={s}",
|
||||
.{
|
||||
linker.options.public_url,
|
||||
base,
|
||||
absolute_pathname.ext,
|
||||
package_version.?,
|
||||
},
|
||||
);
|
||||
var dirname = std.fs.path.dirname(base) orelse "";
|
||||
|
||||
return Fs.Path.initWithPretty(absolute_url, absolute_url);
|
||||
} else {
|
||||
const absolute_url = try std.fmt.allocPrint(
|
||||
linker.allocator,
|
||||
"{s}{s}{s}",
|
||||
.{
|
||||
linker.options.public_url,
|
||||
base,
|
||||
absolute_pathname.ext,
|
||||
},
|
||||
);
|
||||
var basename = std.fs.path.basename(base);
|
||||
|
||||
return Fs.Path.initWithPretty(absolute_url, absolute_url);
|
||||
if (use_hashed_name) {
|
||||
var basepath = Fs.Path.init(source_path);
|
||||
basename = try linker.getHashedFilename(basepath, null);
|
||||
}
|
||||
|
||||
const absolute_url = try std.fmt.allocPrint(
|
||||
linker.allocator,
|
||||
"{s}{s}{s}{s}",
|
||||
.{
|
||||
linker.options.public_url,
|
||||
dirname,
|
||||
basename,
|
||||
absolute_pathname.ext,
|
||||
},
|
||||
);
|
||||
|
||||
return Fs.Path.initWithPretty(absolute_url, absolute_url);
|
||||
},
|
||||
|
||||
else => unreachable,
|
||||
@@ -420,6 +511,7 @@ pub fn NewLinker(comptime BundlerType: type) type {
|
||||
|
||||
pub fn processImportRecord(
|
||||
linker: *ThisLinker,
|
||||
loader: Options.Loader,
|
||||
source_dir: string,
|
||||
resolve_result: *Resolver.Result,
|
||||
import_record: *ImportRecord,
|
||||
@@ -440,6 +532,7 @@ pub fn NewLinker(comptime BundlerType: type) type {
|
||||
source_dir,
|
||||
resolve_result.path_pair.primary.text,
|
||||
if (resolve_result.package_json) |package_json| package_json.version else "",
|
||||
BundlerType.isCacheEnabled and loader == .file,
|
||||
import_path_format,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -607,7 +607,7 @@ pub const BundleOptions = struct {
|
||||
};
|
||||
|
||||
pub const Defaults = struct {
|
||||
pub var ExtensionOrder = [_]string{ ".tsx", ".ts", ".jsx", ".js", ".json" };
|
||||
pub var ExtensionOrder = [_]string{ ".tsx", ".ts", ".jsx", ".js", ".json", ".css" };
|
||||
};
|
||||
|
||||
pub fn fromApi(
|
||||
@@ -860,6 +860,7 @@ pub const OutputFile = struct {
|
||||
fd: FileDescriptorType = 0,
|
||||
dir: FileDescriptorType = 0,
|
||||
is_tmpdir: bool = false,
|
||||
is_outdir: bool = false,
|
||||
|
||||
pub fn fromFile(fd: FileDescriptorType, pathname: string) FileOperation {
|
||||
return .{
|
||||
@@ -939,16 +940,6 @@ pub const OutputFile = struct {
|
||||
|
||||
pub fn copyTo(file: *const OutputFile, base_path: string, rel_path: []u8, dir: FileDescriptorType) !void {
|
||||
var copy = file.value.copy;
|
||||
if (isMac and copy.fd > 0) {
|
||||
// First try using a copy-on-write clonefile()
|
||||
// this will fail if the destination already exists
|
||||
rel_path.ptr[rel_path.len + 1] = 0;
|
||||
var rel_c_path = rel_path.ptr[0..rel_path.len :0];
|
||||
const success = C.fclonefileat(copy.fd, dir, rel_c_path, 0) == 0;
|
||||
if (success) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var dir_obj = std.fs.Dir{ .fd = dir };
|
||||
const file_out = (try dir_obj.createFile(rel_path, .{}));
|
||||
@@ -956,7 +947,7 @@ pub const OutputFile = struct {
|
||||
const fd_out = file_out.handle;
|
||||
var do_close = false;
|
||||
// TODO: close file_out on error
|
||||
const fd_in = if (copy.fd > 0) copy.fd else (try std.fs.openFileAbsolute(copy.getPathname(), .{ .read = true })).handle;
|
||||
const fd_in = (try std.fs.openFileAbsolute(file.input.text, .{ .read = true })).handle;
|
||||
|
||||
if (isNative) {
|
||||
Fs.FileSystem.setMaxFd(fd_out);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const tester = @import("../test/tester.zig");
|
||||
|
||||
const FeatureFlags = @import("../global.zig").FeatureFlags;
|
||||
const FeatureFlags = @import("../feature_flags.zig");
|
||||
const std = @import("std");
|
||||
|
||||
threadlocal var parser_join_input_buffer: [1024]u8 = undefined;
|
||||
@@ -259,7 +259,7 @@ pub fn relativeToCommonPath(
|
||||
var out_slice: []u8 = buf[0..0];
|
||||
|
||||
if (normalized_from.len > 0) {
|
||||
var i: usize = @boolToInt(normalized_from[0] == separator) + 1 + last_common_separator;
|
||||
var i: usize = @intCast(usize, @boolToInt(normalized_from[0] == separator)) + 1 + last_common_separator;
|
||||
|
||||
while (i <= normalized_from.len) : (i += 1) {
|
||||
if (i == normalized_from.len or (normalized_from[i] == separator and i + 1 < normalized_from.len)) {
|
||||
|
||||
BIN
src/test/fixtures/me@2x.jpeg
vendored
Normal file
BIN
src/test/fixtures/me@2x.jpeg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
1205
src/test/fixtures/simple.css
vendored
Normal file
1205
src/test/fixtures/simple.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3
src/test/fixtures/test-import.css
vendored
Normal file
3
src/test/fixtures/test-import.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.bacon {
|
||||
display: block;
|
||||
}
|
||||
Reference in New Issue
Block a user