diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bundler.zig | 16 | ||||
-rw-r--r-- | src/cli.zig | 12 | ||||
-rw-r--r-- | src/options.zig | 31 |
3 files changed, 56 insertions, 3 deletions
diff --git a/src/bundler.zig b/src/bundler.zig index 8b4263c53..87c34a5ff 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -225,6 +225,7 @@ pub fn NewBundler(cache_files: bool) type { log: *logger.Log, tmpfile_byte_offset: u32 = 0, code_end_byte_offset: u32 = 0, + has_jsx: bool = false, pub const current_version: u32 = 1; @@ -317,6 +318,19 @@ pub fn NewBundler(cache_files: bool) type { while (this.resolve_queue.readItem()) |resolved| { try this.processFile(resolved); } + + if (this.has_jsx and this.bundler.options.jsx.supports_fast_refresh) { + if (this.bundler.resolver.resolve( + this.bundler.fs.top_level_dir, + "react-refresh/runtime", + .require, + )) |refresh_runtime| { + if (!this.resolved_paths.contains(refresh_runtime.path_pair.primary.text)) { + try this.processFile(refresh_runtime); + } + } else |err| {} + } + // Ensure we never overflow this.code_end_byte_offset = @truncate( u32, @@ -719,6 +733,7 @@ pub fn NewBundler(cache_files: bool) type { .hash = package.hash, }, ); + this.has_jsx = this.has_jsx or strings.eql(package.name, this.bundler.options.jsx.package_name); } var path_extname_length = @truncate(u8, std.fs.path.extension(package_relative_path).len); @@ -1229,6 +1244,7 @@ pub fn NewBundler(cache_files: bool) type { opts.transform_require_to_import = true; opts.can_import_from_bundle = bundler.options.node_modules_bundle != null; opts.features.hot_module_reloading = bundler.options.hot_module_reloading; + opts.features.react_fast_refresh = opts.features.hot_module_reloading and jsx.parse and bundler.options.jsx.supports_fast_refresh; opts.filepath_hash_for_hmr = file_hash orelse 0; const value = (bundler.resolver.caches.js.parse(allocator, opts, bundler.options.define, bundler.log, &source) catch null) orelse return null; return ParseResult{ diff --git a/src/cli.zig b/src/cli.zig index 744369472..f5d3ed4c0 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -123,7 +123,7 @@ pub const Cli = struct { clap.parseParam("--jsx-runtime <STR> \"automatic\" (default) or \"classic\"") catch unreachable, clap.parseParam("--jsx-production Use jsx instead of jsxDEV (default) for the automatic runtime") catch unreachable, clap.parseParam("--extension-order <STR>... defaults to: .tsx,.ts,.jsx,.js,.json ") catch unreachable, - clap.parseParam("--react-fast-refresh Enable React Fast Refresh (not implemented yet)") catch unreachable, + clap.parseParam("--disable-react-fast-refresh Disable React Fast Refresh. Enabled if --serve is set and --jsx-production is not set. Otherwise, it's a noop.") catch unreachable, clap.parseParam("--tsconfig-override <STR> Load tsconfig from path instead of cwd/tsconfig.json") catch unreachable, clap.parseParam("--platform <STR> \"browser\" or \"node\". Defaults to \"browser\"") catch unreachable, clap.parseParam("--main-fields <STR>... Main fields to lookup in package.json. Defaults to --platform dependent") catch unreachable, @@ -181,7 +181,15 @@ pub const Cli = struct { var jsx_import_source = args.option("--jsx-import-source"); var jsx_runtime = args.option("--jsx-runtime"); var jsx_production = args.flag("--jsx-production"); - var react_fast_refresh = args.flag("--react-fast-refresh"); + var react_fast_refresh = false; + + if (serve or args.flag("--new-jsb")) { + react_fast_refresh = true; + if (args.flag("--disable-react-fast-refresh") or jsx_production) { + react_fast_refresh = false; + } + } + var main_fields = args.options("--main-fields"); var node_modules_bundle_path = args.option("--jsb") orelse brk: { diff --git a/src/options.zig b/src/options.zig index e9f48ee17..54483e801 100644 --- a/src/options.zig +++ b/src/options.zig @@ -389,11 +389,36 @@ pub const JSX = struct { /// /** @jsxImportSource @emotion/core */ import_source: string = "react/jsx-dev-runtime", classic_import_source: string = "react", + package_name: []const u8 = "react", + supports_fast_refresh: bool = false, jsx: string = "jsxDEV", development: bool = true, parse: bool = true, + + pub fn parsePackageName(str: string) string { + if (str[0] == '@') { + if (strings.indexOfChar(str[1..], '/')) |first_slash| { + var remainder = str[1 + first_slash + 1 ..]; + + if (strings.indexOfChar(remainder, '/')) |last_slash| { + return str[0 .. first_slash + 1 + last_slash + 1]; + } + } + } + + if (strings.indexOfChar(str, '/')) |first_slash| { + return str[0..first_slash]; + } + + return str; + } + + pub fn isReactLike(pragma: *const Pragma) bool { + return strings.eqlComptime(pragma.package_name, "react") or strings.eqlComptime(pragma.package_name, "@emotion/jsx") or strings.eqlComptime(pragma.package_name, "@emotion/react"); + } + pub const Defaults = struct { pub var Factory = [_]string{ "React", "createElement" }; pub var Fragment = [_]string{ "React", "Fragment" }; @@ -453,12 +478,17 @@ pub const JSX = struct { if (jsx.import_source.len > 0) { pragma.import_source = jsx.import_source; + pragma.package_name = parsePackageName(pragma.import_source); + pragma.supports_fast_refresh = pragma.development and pragma.isReactLike(); } else if (jsx.development) { pragma.import_source = Defaults.ImportSourceDev; pragma.jsx = Defaults.JSXFunctionDev; + pragma.supports_fast_refresh = true; + pragma.package_name = "react"; } else { pragma.import_source = Defaults.ImportSource; pragma.jsx = Defaults.JSXFunction; + pragma.supports_fast_refresh = false; } pragma.development = jsx.development; @@ -565,7 +595,6 @@ pub const BundleOptions = struct { resolve_dir: string = "/", jsx: JSX.Pragma = JSX.Pragma{}, - react_fast_refresh: bool = false, hot_module_reloading: bool = false, inject: ?[]string = null, public_url: string = "", |