@@ -31,6 +31,20 @@ pub fn build(b: *std.Build) void {
3131 const core_mod = core_dep .module ("turboapi-core" );
3232 mer_mod .addImport ("turboapi-core" , core_mod );
3333
34+ // Self-referential import: internal files (server.zig, router.zig, …)
35+ // file-imported from mer.zig still resolve their `@import("mer")` calls.
36+ mer_mod .addImport ("mer" , mer_mod );
37+
38+ // ── Expose framework internals as named modules for consumer projects ────
39+ // Consumers do: `merjs_dep.module("server")` in their build.zig.
40+ // Each module has "mer" wired so transitive file-imports just work.
41+ const server_mod = b .addModule ("server" , .{ .root_source_file = b .path ("src/server.zig" ) });
42+ server_mod .addImport ("mer" , mer_mod );
43+ const watcher_named = b .addModule ("watcher" , .{ .root_source_file = b .path ("src/watcher.zig" ) });
44+ _ = watcher_named ;
45+ const prerender_mod = b .addModule ("prerender" , .{ .root_source_file = b .path ("src/prerender.zig" ) });
46+ prerender_mod .addImport ("mer" , mer_mod );
47+
3448 // ── Demo site (examples/site) ───────────────────────────────────────────
3549 const counter_config_mod = b .addModule ("counter_config" , .{
3650 .root_source_file = b .path ("examples/site/wasm/counter_config.zig" ),
@@ -56,12 +70,6 @@ pub fn build(b: *std.Build) void {
5670 const install_kuri = b .addInstallArtifact (kuri_dep .artifact ("kuri" ), .{});
5771 b .getInstallStep ().dependOn (& install_kuri .step );
5872
59- // ── `zig build serve` ────────────────────────────────────────────────────
60- const run_exe = b .addRunArtifact (exe );
61- run_exe .step .dependOn (b .getInstallStep ());
62- if (b .args ) | args | run_exe .addArgs (args );
63- b .step ("serve" , "Start the merjs dev server" ).dependOn (& run_exe .step );
64-
6573 // ── Codegen ──────────────────────────────────────────────────────────────
6674 const codegen_exe = b .addExecutable (.{
6775 .name = "codegen" ,
@@ -75,6 +83,15 @@ pub fn build(b: *std.Build) void {
7583 run_codegen .setCwd (b .path ("." ));
7684 b .step ("codegen" , "Regenerate src/generated/routes.zig" ).dependOn (& run_codegen .step );
7785
86+ // ── Auto-run codegen before compiling (fresh clones just work) ───────────
87+ exe .step .dependOn (& run_codegen .step );
88+
89+ // ── `zig build serve` ────────────────────────────────────────────────────
90+ const run_exe = b .addRunArtifact (exe );
91+ run_exe .step .dependOn (b .getInstallStep ());
92+ if (b .args ) | args | run_exe .addArgs (args );
93+ b .step ("serve" , "Start the merjs dev server" ).dependOn (& run_exe .step );
94+
7895 // ── Prerender (SSG) ─────────────────────────────────────────────────────
7996 const run_prerender = b .addRunArtifact (exe );
8097 run_prerender .addArg ("--prerender" );
@@ -120,6 +137,8 @@ pub fn build(b: *std.Build) void {
120137 const worker_wasm = b .addExecutable (.{ .name = "merjs" , .root_module = worker_mod });
121138 worker_wasm .rdynamic = true ;
122139 worker_wasm .entry = .disabled ;
140+ // Auto-run codegen before worker compilation too.
141+ worker_wasm .step .dependOn (& run_codegen .step );
123142 const install_worker = b .addInstallFile (worker_wasm .getEmittedBin (), "../examples/site/worker/merjs.wasm" );
124143 const worker_step = b .step ("worker" , "Compile worker WASM for Cloudflare Workers" );
125144 worker_step .dependOn (& install_worker .step );
@@ -152,6 +171,8 @@ pub fn build(b: *std.Build) void {
152171 helpers .addDirModules (b , test_mod , mer_mod , "examples/site/api" , "api" , &.{});
153172 helpers .addRoutesModule (b , test_mod , mer_mod , "src/generated/routes.zig" , "examples/site/app" , "examples/site/api" , site_extras );
154173 const run_tests = b .addRunArtifact (b .addTest (.{ .root_module = test_mod }));
174+ // Auto-run codegen before tests too.
175+ run_tests .step .dependOn (& run_codegen .step );
155176 const test_step = b .step ("test" , "Run unit tests" );
156177 test_step .dependOn (& run_tests .step );
157178 // Run inline tests in individual framework source files.
@@ -163,37 +184,34 @@ pub fn build(b: *std.Build) void {
163184 });
164185 test_step .dependOn (& b .addRunArtifact (b .addTest (.{ .root_module = file_test_mod })).step );
165186 }
166- // Run router inline tests.
187+ // Run router + runtime inline tests (through mer.zig as root to avoid
188+ // file-ownership conflict: mer.zig file-imports router.zig/server.zig/etc.,
189+ // so those files belong to the mer module and can't also be test roots).
167190 {
168- const router_test_mod = b .createModule (.{
169- .root_source_file = b .path ("src/router .zig" ),
191+ const mer_test_mod = b .createModule (.{
192+ .root_source_file = b .path ("src/mer .zig" ),
170193 .target = target ,
171194 .optimize = optimize ,
172195 });
173- router_test_mod .addImport ("mer" , mer_mod );
174- test_step .dependOn (& b .addRunArtifact (b .addTest (.{ .root_module = router_test_mod })).step );
196+ mer_test_mod .addImport ("dhi_model" , dhi_model_mod );
197+ mer_test_mod .addImport ("dhi_validator" , dhi_validator_mod );
198+ mer_test_mod .addImport ("turboapi-core" , core_mod );
199+ mer_test_mod .addImport ("mer" , mer_test_mod );
200+ test_step .dependOn (& b .addRunArtifact (b .addTest (.{ .root_module = mer_test_mod })).step );
175201 }
176202
177- // ── Consumer integration test (issue #62) ──────────────────────────────
178- // Simulates a consumer project with its own routes — proves the named
179- // module override works and framework example routes don't leak in.
203+ // ── Consumer integration test (issue #62, #69) ────────────────────────
204+ // Simulates a consumer project with its own routes — proves that
205+ // `mer.Router.fromGenerated` works and framework example routes don't leak in.
206+ // With the self-referential mer import, no manual wiring of ssr.zig/router.zig
207+ // transitive deps is needed — consumers just use `@import("mer")`.
180208 {
181209 const consumer_test_mod = b .createModule (.{
182210 .root_source_file = b .path ("tests/consumer/src/test_consumer_routes.zig" ),
183211 .target = target ,
184212 .optimize = optimize ,
185213 });
186214 consumer_test_mod .addImport ("mer" , mer_mod );
187- // Give the test access to ssr.zig (framework internals).
188- consumer_test_mod .addImport ("ssr.zig" , b .createModule (.{
189- .root_source_file = b .path ("src/ssr.zig" ),
190- }));
191- // Wire ssr.zig's dependencies.
192- consumer_test_mod .import_table .get ("ssr.zig" ).? .addImport ("mer" , mer_mod );
193- consumer_test_mod .import_table .get ("ssr.zig" ).? .addImport ("router.zig" , b .createModule (.{
194- .root_source_file = b .path ("src/router.zig" ),
195- }));
196- consumer_test_mod .import_table .get ("ssr.zig" ).? .import_table .get ("router.zig" ).? .addImport ("mer" , mer_mod );
197215 // The key: wire "routes" to the CONSUMER's routes, not the framework's.
198216 const consumer_routes_mod = b .createModule (.{
199217 .root_source_file = b .path ("tests/consumer/src/routes.zig" ),
@@ -210,7 +228,7 @@ pub fn build(b: *std.Build) void {
210228 consumer_routes_mod .addImport (page [0 ], page_mod );
211229 consumer_test_mod .addImport (page [0 ], page_mod );
212230 }
213- consumer_test_mod .import_table . get ( "ssr.zig" ) .? . addImport ("routes" , consumer_routes_mod );
231+ consumer_test_mod .addImport ("routes" , consumer_routes_mod );
214232 test_step .dependOn (& b .addRunArtifact (b .addTest (.{ .root_module = consumer_test_mod })).step );
215233 }
216234
@@ -241,15 +259,9 @@ pub fn build(b: *std.Build) void {
241259 .optimize = optimize ,
242260 });
243261 desktop_mod .addImport ("mer" , mer_mod );
244- const merjs_internal = b .createModule (.{
245- .root_source_file = b .path ("src/desktop_shim.zig" ),
246- });
247- merjs_internal .addImport ("mer" , mer_mod );
248- helpers .addDirModules (b , merjs_internal , mer_mod , "examples/site/app" , "app" , site_extras );
249- helpers .addDirModules (b , merjs_internal , mer_mod , "examples/site/api" , "api" , &.{});
250- desktop_mod .addImport ("merjs_internal" , merjs_internal );
251262 helpers .addDirModules (b , desktop_mod , mer_mod , "examples/site/app" , "app" , site_extras );
252263 helpers .addDirModules (b , desktop_mod , mer_mod , "examples/site/api" , "api" , &.{});
264+ helpers .addRoutesModule (b , desktop_mod , mer_mod , "src/generated/routes.zig" , "examples/site/app" , "examples/site/api" , site_extras );
253265 const desktop_exe = b .addExecutable (.{ .name = "merapp" , .root_module = desktop_mod });
254266 desktop_exe .linkFramework ("AppKit" );
255267 desktop_exe .linkFramework ("WebKit" );
@@ -268,7 +280,7 @@ pub fn build(b: *std.Build) void {
268280 \\ <key>CFBundleExecutable</key> <string>merapp</string>
269281 \\ <key>CFBundleIdentifier</key> <string>com.merjs.desktop</string>
270282 \\ <key>CFBundleName</key> <string>MerApp</string>
271- \\ <key>CFBundleVersion</key> <string>0.2.0 </string>
283+ \\ <key>CFBundleVersion</key> <string>0.2.2 </string>
272284 \\ <key>NSHighResolutionCapable</key><true/>
273285 \\ <key>NSPrincipalClass</key> <string>NSApplication</string>
274286 \\</dict>
0 commit comments