Starting to work on rutnime

Former-commit-id: 23220fd348
This commit is contained in:
Jarred Sumner
2021-05-19 19:30:24 -07:00
parent 2884b759c3
commit a58adfcaa2
15 changed files with 278 additions and 65 deletions

65
.vscode/launch.json vendored
View File

@@ -28,21 +28,21 @@
// "cwd": "${workspaceFolder}",
// "console": "internalConsole"
// }
{
"type": "lldb",
"request": "launch",
"name": "Dev Launch",
"program": "${workspaceFolder}/build/debug/macos-x86_64/esdev",
"preLaunchTask": "build",
"args": [
"--resolve=disable",
"--cwd",
"/Users/jarredsumner/Code/esdev/src/test/fixtures",
"defines.js"
],
"cwd": "${workspaceFolder}",
"console": "internalConsole"
}
// {
// "type": "lldb",
// "request": "launch",
// "name": "Dev Launch",
// "program": "${workspaceFolder}/build/debug/macos-x86_64/esdev",
// "preLaunchTask": "build",
// "args": [
// "--resolve=disable",
// "--cwd",
// "/Users/jarredsumner/Code/esdev/src/test/fixtures",
// "escape-chars.js"
// ],
// "cwd": "${workspaceFolder}",
// "console": "internalConsole"
// }
// {
// "type": "lldb",
// "request": "launch",
@@ -77,23 +77,24 @@
// "cwd": "${workspaceFolder}",
// "console": "internalConsole"
// }
// {
// "type": "lldb",
// "request": "launch",
// "name": "Dev Launch",
// "program": "${workspaceFolder}/build/debug/macos-x86_64/esdev",
// "preLaunchTask": "build",
// "args": [
// "--resolve=dev",
// "--cwd",
// "./src/api/demo",
// "pages/index.js",
// "-o",
// "out"
// ],
// "cwd": "${workspaceFolder}",
// "console": "internalConsole"
// }
{
"type": "lldb",
"request": "launch",
"name": "Dev Launch",
"program": "${workspaceFolder}/build/debug/macos-x86_64/esdev",
"preLaunchTask": "build",
"args": [
"--resolve=dev",
"--cwd",
"./src/api/demo",
"pages/index.jsx",
"-o",
"out",
"--public-url=https://hello.com/"
],
"cwd": "${workspaceFolder}",
"console": "internalConsole"
}
// {
// "type": "lldb",
// "request": "launch",

View File

@@ -8,6 +8,9 @@ api:
speedy-prod-native-macos:
zig build -Drelease-fast -Dtarget=x86_64-macos-gnu
speedy-prod-native-macos-lib:
zig build lib -Drelease-fast -Dtarget=x86_64-macos-gnu
speedy-m1:
zig build -Drelease-fast -Dtarget=aarch64-macos-gnu

View File

@@ -33,6 +33,10 @@ pub const Ref = packed struct {
.inner_index = std.math.maxInt(Ref.Int),
.source_index = std.math.maxInt(Ref.Int),
};
pub const RuntimeRef = Ref{
.inner_index = std.math.maxInt(Ref.Int),
.source_index = std.math.maxInt(Ref.Int) - 1,
};
pub fn toInt(int: anytype) Int {
return @intCast(Int, int);
}

View File

@@ -20,7 +20,7 @@ const sync = @import("sync.zig");
const ThreadPool = sync.ThreadPool;
const ThreadSafeHashMap = @import("./thread_safe_hash_map.zig");
const ImportRecord = @import("./import_record.zig").ImportRecord;
// pub const
const allocators = @import("./allocators.zig");
// const BundleMap =
const ResolveResults = ThreadSafeHashMap.ThreadSafeStringHashMap(Resolver.Resolver.Result);
pub const Bundler = struct {
@@ -35,6 +35,12 @@ pub const Bundler = struct {
resolve_results: *ResolveResults,
resolve_queue: std.fifo.LinearFifo(Resolver.Resolver.Result, std.fifo.LinearFifoBufferType.Dynamic),
elapsed: i128 = 0,
needs_runtime: bool = false,
runtime_output_path: Fs.Path = undefined,
pub const RuntimeCode = @embedFile("./runtime.js");
// to_bundle:
// thread_pool: *ThreadPool,
@@ -46,6 +52,8 @@ pub const Bundler = struct {
) !Bundler {
var fs = try Fs.FileSystem.init1(allocator, opts.absolute_working_dir, opts.watch orelse false);
const bundle_options = try options.BundleOptions.fromApi(allocator, fs, log, opts);
relative_paths_list = ImportPathsList.init(allocator);
// var pool = try allocator.create(ThreadPool);
// try pool.init(ThreadPool.InitConfig{
// .allocator = allocator,
@@ -64,26 +72,75 @@ pub const Bundler = struct {
};
}
pub fn processImportRecord(bundler: *Bundler, source_dir: string, import_record: *ImportRecord) !void {
var resolve_result = (bundler.resolver.resolve(source_dir, import_record.path.text, import_record.kind) catch null) orelse return;
const ImportPathsList = allocators.BSSStringList(2048, 256);
var relative_paths_list: *ImportPathsList = undefined;
threadlocal var relative_path_allocator: std.heap.FixedBufferAllocator = undefined;
threadlocal var relative_path_allocator_buf: [4096]u8 = undefined;
threadlocal var relative_path_allocator_buf_loaded: bool = false;
if (!bundler.resolve_results.contains(resolve_result.path_pair.primary.text)) {
try bundler.resolve_results.put(resolve_result.path_pair.primary.text, resolve_result);
try bundler.resolve_queue.writeItem(resolve_result);
pub fn generateImportPath(bundler: *Bundler, source_dir: string, source_path: string) !Fs.Path {
if (!relative_path_allocator_buf_loaded) {
relative_path_allocator_buf_loaded = true;
relative_path_allocator = std.heap.FixedBufferAllocator.init(&relative_path_allocator_buf);
}
defer relative_path_allocator.reset();
if (!strings.eql(import_record.path.text, resolve_result.path_pair.primary.text)) {
import_record.path = Fs.Path.init(resolve_result.path_pair.primary.text);
switch (bundler.options.import_path_format) {
.relative => {
const relative_path_temp = try std.fs.path.relative(&relative_path_allocator.allocator, source_dir, source_path);
const relative_path = try relative_paths_list.append(relative_path_temp);
return Fs.Path.init(relative_path);
},
.absolute_url => {
if (!relative_path_allocator_buf_loaded) {
relative_path_allocator_buf_loaded = true;
relative_path_allocator = std.heap.FixedBufferAllocator.init(&relative_path_allocator_buf);
}
const relative_path_temp = try std.fs.path.relative(&relative_path_allocator.allocator, bundler.fs.top_level_dir, source_path);
const relative_path = try relative_paths_list.append(try std.fmt.allocPrint(&relative_path_allocator.allocator, "{s}{s}", .{ bundler.options.public_url, relative_path_temp }));
return Fs.Path.init(relative_path);
},
}
}
pub fn buildWithResolveResult(bundler: *Bundler, resolve_result: Resolver.Resolver.Result) !void {
pub fn processImportRecord(bundler: *Bundler, source_dir: string, import_record: *ImportRecord) !void {
var resolve_result = (bundler.resolver.resolve(source_dir, import_record.path.text, import_record.kind) catch null) orelse return;
// extremely naive.
resolve_result.is_from_node_modules = strings.contains(resolve_result.path_pair.primary.text, "/node_modules");
if (resolve_result.shouldAssumeCommonJS()) {
import_record.wrap_with_to_module = true;
if (!bundler.needs_runtime) {
bundler.runtime_output_path = Fs.Path.init(try std.fmt.allocPrint(bundler.allocator, "{s}/__runtime.js", .{bundler.fs.top_level_dir}));
}
bundler.needs_runtime = true;
}
// lazy means:
// Run the resolver
// Don't parse/print automatically.
if (bundler.options.resolve_mode != .lazy) {
if (!bundler.resolve_results.contains(resolve_result.path_pair.primary.text)) {
try bundler.resolve_results.put(resolve_result.path_pair.primary.text, resolve_result);
try bundler.resolve_queue.writeItem(resolve_result);
}
}
if (!strings.eql(import_record.path.text, resolve_result.path_pair.primary.text)) {
import_record.path = try bundler.generateImportPath(source_dir, resolve_result.path_pair.primary.text);
}
}
pub fn buildWithResolveResult(bundler: *Bundler, resolve_result: Resolver.Resolver.Result) !?options.OutputFile {
if (resolve_result.is_external) {
return;
return null;
}
// Step 1. Parse & scan
const result = bundler.parse(resolve_result.path_pair.primary) orelse return;
const result = bundler.parse(resolve_result.path_pair.primary) orelse return null;
switch (result.loader) {
.jsx, .js, .ts, .tsx => {
@@ -99,7 +156,7 @@ pub const Bundler = struct {
else => {},
}
try bundler.print(
return try bundler.print(
result,
);
}
@@ -107,7 +164,7 @@ pub const Bundler = struct {
pub fn print(
bundler: *Bundler,
result: ParseResult,
) !void {
) !options.OutputFile {
var allocator = bundler.allocator;
const relative_path = try std.fs.path.relative(bundler.allocator, bundler.fs.top_level_dir, result.source.path.text);
var out_parts = [_]string{ bundler.options.output_dir, relative_path };
@@ -124,13 +181,13 @@ pub const Bundler = struct {
js_ast.Symbol.Map.initList(symbols),
&result.source,
false,
js_printer.Options{ .to_module_ref = ast.module_ref orelse js_ast.Ref{ .inner_index = 0 } },
js_printer.Options{ .to_module_ref = Ref.RuntimeRef },
&_linker,
);
try bundler.output_files.append(options.OutputFile{
return options.OutputFile{
.path = out_path,
.contents = print_result.js,
});
};
}
pub const ParseResult = struct {
@@ -192,6 +249,24 @@ pub const Bundler = struct {
return null;
}
pub fn buildFile(
bundler: *Bundler,
allocator: *std.mem.Allocator,
relative_path: string,
) !options.TransformResult {
var log = logger.Log.init(bundler.allocator);
var original_resolver_logger = bundler.resolver.log;
var original_bundler_logger = bundler.log;
defer bundler.log = original_bundler_logger;
defer bundler.resolver.log = original_resolver_logger;
bundler.log = log;
bundler.resolver.log = log;
const resolved = try bundler.resolver.resolve(bundler.fs.top_level_dir, relative_path, .entry_point);
const output_file = try bundler.buildWithResolveResult(resolved);
var output_files = try allocator.alloc(options.OutputFile, 1);
return try options.TransformResult.init(output_files, log, allocator);
}
pub fn bundle(
allocator: *std.mem.Allocator,
log: *logger.Log,
@@ -263,7 +338,11 @@ pub const Bundler = struct {
}
try bundler.resolve_results.put(key, result);
entry_points[entry_point_i] = result;
Output.print("Resolved {s} => {s}", .{ entry, result.path_pair.primary.text });
if (isDebug) {
Output.print("Resolved {s} => {s}", .{ entry, result.path_pair.primary.text });
}
entry_point_i += 1;
bundler.resolve_queue.writeItem(result) catch unreachable;
}
@@ -276,12 +355,19 @@ pub const Bundler = struct {
switch (bundler.options.resolve_mode) {
.lazy, .dev, .bundle => {
while (bundler.resolve_queue.readItem()) |item| {
bundler.buildWithResolveResult(item) catch continue;
const output_file = bundler.buildWithResolveResult(item) catch continue orelse continue;
bundler.output_files.append(output_file) catch unreachable;
}
},
else => Global.panic("Unsupported resolve mode: {s}", .{@tagName(bundler.options.resolve_mode)}),
}
// if (bundler.needs_runtime) {
// try bundler.output_files.append(options.OutputFile{
// });
// }
if (enableTracing) {
Output.print(
"\n---Tracing---\nResolve time: {d}\nParsing time: {d}\n---Tracing--\n\n",

View File

@@ -195,7 +195,7 @@ pub const Cli = struct {
else => {
diag.name.long = "--resolve";
diag.arg = _resolve;
try diag.report(stderr.writer(), error.InvalidPlatform);
try diag.report(stderr.writer(), error.InvalidResolveOption);
std.process.exit(1);
},
}

View File

@@ -1425,6 +1425,8 @@ pub const Parser = struct {
}
};
var runtime_import_names = []string{ "__markAsModule", "__commonJS", "__reExport", "__toModule" };
pub fn parse(self: *Parser) !js_ast.Result {
if (self.p == null) {
self.p = try P.init(self.allocator, self.log, self.source, self.define, self.lexer, self.options);
@@ -1696,6 +1698,10 @@ pub const Prefill = 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";
pub var ToModule = "__toModule";
};
};
@@ -9110,8 +9116,6 @@ pub const P = struct {
e_.expr = p.visitExpr(e_.expr);
return p.import_transposer.maybeTransposeIf(e_.expr, state);
// TODO: maybeTransposeIfExprChain
},
.e_call => |e_| {
p.call_target = e_.target.data;
@@ -11228,11 +11232,11 @@ pub const P = struct {
return js_ast.Ast{
.parts = parts,
.module_scope = p.module_scope.*,
.symbols = p.symbols.toOwnedSlice(),
.symbols = p.symbols.items,
.exports_ref = p.exports_ref,
.wrapper_ref = wrapper,
.import_records = p.import_records.toOwnedSlice(),
.export_star_import_records = p.export_star_import_records.toOwnedSlice(),
.import_records = p.import_records.items,
.export_star_import_records = p.export_star_import_records.items,
.top_level_symbol_to_parts = p.top_level_symbol_to_parts,
.approximate_line_count = p.lexer.approximate_newline_count + 1,
.exports_kind = exports_kind,

20
src/lib.zig Normal file
View File

@@ -0,0 +1,20 @@
const std = @import("std");
const lex = @import("js_lexer.zig");
const logger = @import("logger.zig");
const alloc = @import("alloc.zig");
const options = @import("options.zig");
const js_parser = @import("js_parser.zig");
const json_parser = @import("json_parser.zig");
const js_printer = @import("js_printer.zig");
const js_ast = @import("js_ast.zig");
const linker = @import("linker.zig");
usingnamespace @import("ast/base.zig");
usingnamespace @import("defines.zig");
usingnamespace @import("global.zig");
const panicky = @import("panic_handler.zig");
const cli = @import("cli.zig");
const api = @import("./api/schema.zig");
extern const Configuration = struct {};
export fn configure(configuration: Configuration) void {}

View File

@@ -283,7 +283,7 @@ pub const BundleOptions = struct {
jsx: JSX.Pragma = JSX.Pragma{},
react_fast_refresh: bool = false,
inject: ?[]string = null,
public_url: string = "/",
public_url: string = "",
output_dir: string = "",
write: bool = false,
preserve_symlinks: bool = false,
@@ -295,6 +295,12 @@ pub const BundleOptions = struct {
external: ExternalModules = ExternalModules{},
entry_points: []const string,
extension_order: []const string = &Defaults.ExtensionOrder,
import_path_format: ImportPathFormat = ImportPathFormat.relative,
pub const ImportPathFormat = enum {
relative,
absolute_url,
};
pub const Defaults = struct {
pub var ExtensionOrder = [_]string{ ".tsx", ".ts", ".jsx", ".js", ".json" };
@@ -350,6 +356,11 @@ pub const BundleOptions = struct {
.entry_points = transform.entry_points,
};
if (transform.public_url) |public_url| {
opts.import_path_format = ImportPathFormat.absolute_url;
opts.public_url = public_url;
}
if (transform.jsx) |jsx| {
opts.jsx = try JSX.Pragma.fromApi(jsx, allocator);
}
@@ -380,7 +391,7 @@ pub const TransformOptions = struct {
jsx: ?JSX.Pragma,
react_fast_refresh: bool = false,
inject: ?[]string = null,
public_url: string = "/",
public_url: string = "",
preserve_symlinks: bool = false,
entry_point: Fs.File,
resolve_paths: bool = false,

View File

@@ -3,6 +3,9 @@ usingnamespace @import("global.zig");
const std = @import("std");
const logger = @import("logger.zig");
// This is...poorly named
// It does not rename
// It merely names
pub const Renamer = struct {
symbols: js_ast.Symbol.Map,
source: *const logger.Source,

View File

@@ -250,6 +250,13 @@ pub const Resolver = struct {
debug_meta: ?DebugMeta = null,
// Most NPM modules are CommonJS
// If unspecified, assume CommonJS.
// If internal app code, assume ESM. Since this is designed for ESM.`
pub fn shouldAssumeCommonJS(r: *Result) bool {
return r.is_from_node_modules and r.module_type != .esm;
}
pub const DebugMeta = struct {
notes: std.ArrayList(logger.Data),
suggestion_text: string = "",
@@ -416,7 +423,11 @@ pub const Resolver = struct {
if (dir_info.tsconfig_json) |tsconfig| {
if (tsconfig.paths.count() > 0) {
if (r.matchTSConfigPaths(tsconfig, import_path, kind)) |res| {
return Result{ .path_pair = res.path_pair, .diff_case = res.diff_case };
return Result{
.path_pair = res.path_pair,
.diff_case = res.diff_case,
.is_from_node_modules = res.is_node_module,
};
}
}
}
@@ -439,7 +450,7 @@ pub const Resolver = struct {
// Run node's resolution rules (e.g. adding ".js")
if (r.loadAsFileOrDirectory(import_path, kind)) |entry| {
return Result{ .path_pair = entry.path_pair, .diff_case = entry.diff_case };
return Result{ .path_pair = entry.path_pair, .diff_case = entry.diff_case, .is_from_node_modules = entry.is_node_module };
}
return null;
@@ -490,7 +501,12 @@ pub const Resolver = struct {
}
if (r.resolveWithoutRemapping(import_dir_info, remap, kind)) |_result| {
result = Result{ .path_pair = _result.path_pair, .diff_case = _result.diff_case };
result = Result{
.path_pair = _result.path_pair,
.diff_case = _result.diff_case,
.is_from_node_modules = _result.is_node_module,
.module_type = pkg.module_type,
};
check_relative = false;
check_package = false;
}
@@ -502,7 +518,11 @@ pub const Resolver = struct {
if (check_relative) {
if (r.loadAsFileOrDirectory(abs_path, kind)) |res| {
check_package = false;
result = Result{ .path_pair = res.path_pair, .diff_case = res.diff_case };
result = Result{
.path_pair = res.path_pair,
.diff_case = res.diff_case,
.is_from_node_modules = res.is_node_module,
};
} else if (!check_package) {
return null;
}
@@ -565,7 +585,11 @@ pub const Resolver = struct {
}
if (r.resolveWithoutRemapping(source_dir_info, import_path, kind)) |res| {
result = Result{ .path_pair = res.path_pair, .diff_case = res.diff_case };
result = Result{
.path_pair = res.path_pair,
.diff_case = res.diff_case,
.is_from_node_modules = res.is_node_module,
};
} else {
// Note: node's "self references" are not currently supported
return null;
@@ -579,11 +603,13 @@ pub const Resolver = struct {
const dir_info = base_dir_info.getEnclosingBrowserScope() orelse continue;
const pkg_json = dir_info.package_json orelse continue;
const rel_path = std.fs.path.relative(r.allocator, pkg_json.source.key_path.text, path.text) catch continue;
result.module_type = pkg_json.module_type;
if (r.checkBrowserMap(pkg_json, rel_path)) |remapped| {
if (remapped.len == 0) {
r.allocator.free(rel_path);
path.is_disabled = true;
} else if (r.resolveWithoutRemapping(dir_info, remapped, kind)) |remapped_result| {
result.is_from_node_modules = remapped_result.is_node_module;
switch (iter.index) {
0 => {
result.path_pair.primary = remapped_result.path_pair.primary;

40
src/runtime.js Normal file
View File

@@ -0,0 +1,40 @@
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
export var __markAsModule = (target) =>
__defProp(target, "__esModule", { value: true });
export var __commonJS = (cb, mod) => () => {
return mod || cb((mod = { exports: {} }).exports, mod), mod.exports;
};
export var __reExport = (target, module, desc) => {
if ((module && typeof module === "object") || typeof module === "function") {
for (let key of __getOwnPropNames(module))
if (!__hasOwnProp.call(target, key) && key !== "default")
__defProp(target, key, {
get: () => module[key],
enumerable:
!(desc = __getOwnPropDesc(module, key)) || desc.enumerable,
});
}
return target;
};
export var __toModule = (module) => {
return __reExport(
__markAsModule(
__defProp(
module != null ? __create(__getProtoOf(module)) : {},
"default",
module && module.__esModule && "default" in module
? { get: () => module.default, enumerable: true }
: { value: module, enumerable: true }
)
),
module
);
};

14
src/runtime.zig Normal file
View File

@@ -0,0 +1,14 @@
pub const Runtime = struct {
pub const Features = packed struct {
react_fast_refresh: bool = false,
hot_module_reloading: bool = false,
keep_names_for_arrow_functions: bool = true,
};
pub const Functions = enum {
KeepNames,
CommonJSToESModule,
TypeScriptDecorateClass,
TypeScriptDecorateParam,
};
};

1
src/test/fixtures/escape-chars.js vendored Normal file
View File

@@ -0,0 +1 @@
console.log("\u2028");

View File

@@ -1,5 +1,3 @@
import * as React from "react";
export function Welcome() {
return <div>Hi.</div>;
}

2
src/test/fixtures/spread-bug.js vendored Normal file
View File

@@ -0,0 +1,2 @@
// spread
const { currentUserId } = cookies(ctx);