diff options
author | 2021-08-09 02:21:31 -0700 | |
---|---|---|
committer | 2021-08-09 02:21:31 -0700 | |
commit | f74771144e71e77969fe50d250818e2fcc0800bd (patch) | |
tree | 85b18e33fc8a7d5c8a8438d8af23439cef74b949 | |
parent | 687b22908f15020d254eb90672bcdddbdaad7f06 (diff) | |
download | bun-f74771144e71e77969fe50d250818e2fcc0800bd.tar.gz bun-f74771144e71e77969fe50d250818e2fcc0800bd.tar.zst bun-f74771144e71e77969fe50d250818e2fcc0800bd.zip |
Split up + generate client & server bundles, support framework +router in GenerateNodeModulesBundle , read framework from package.json + rename "publicURL" to "origin" + add import.meta.filepath
Former-commit-id: 1e76ebb5375247231181ec19a6396c6acf4684fb
35 files changed, 2569 insertions, 1724 deletions
diff --git a/demos/css-stress-test/tsconfig.json b/demos/css-stress-test/tsconfig.json index c13e650d0..37493d0a5 100644 --- a/demos/css-stress-test/tsconfig.json +++ b/demos/css-stress-test/tsconfig.json @@ -9,10 +9,11 @@ "noEmit": true, "esModuleInterop": true, "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "Node", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve" + "jsx": "preserve", + "baseUrl": "." }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"] diff --git a/examples/nexty/framework.client.development.tsx b/examples/nexty/framework.client.development.tsx new file mode 100644 index 000000000..65510c1ce --- /dev/null +++ b/examples/nexty/framework.client.development.tsx @@ -0,0 +1,4 @@ +import * as ReactDOM from "react-dom"; +export default function start(EntryPointNamespace) { + ReactDOM.render(EntryPointNamespace.default); +} diff --git a/examples/nexty/framework.server.development.tsx b/examples/nexty/framework.server.development.tsx new file mode 100644 index 000000000..0e28dac65 --- /dev/null +++ b/examples/nexty/framework.server.development.tsx @@ -0,0 +1,46 @@ +import ReactDOMServer from "react-dom/server.browser"; + +addEventListener("fetch", async (event: FetchEvent) => { + var route = Wundle.match(event); + + console.log("Main:", Wundle.main); + console.log("cwd:", Wundle.cwd); + console.log("Origin:", Wundle.origin); + + const { default: PageComponent } = await import(route.filePath); + // This returns all .css files that were imported in the line above. + // It's recursive, so any file that imports a CSS file will be included. + const stylesheets = Wundle.getImportedStyles() as string[]; + + const response = new Response(` + <!DOCTYPE html> +<html> + <head> + ${stylesheets + .map((style) => `<link rel="stylesheet" href="${style}">`) + .join("\n")} + + <link + rel="stylesheet" + crossorigin="anonymous" + href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;700&family=Space+Mono:wght@400;700" + /> + </head> + <body> + + <div id="reactroot">${ReactDOMServer.renderToString( + <PageComponent /> + )}</div> + + <script src="${route.scriptSrc}" async type="module"></script> + </body> +</html> + `); + + event.respondWith(response); +}); + +// typescript isolated modules +export {}; + +declare var Wundle: any; diff --git a/examples/nexty/framework.server.production.tsx b/examples/nexty/framework.server.production.tsx new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/examples/nexty/framework.server.production.tsx diff --git a/examples/nexty/index.js b/examples/nexty/index.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/examples/nexty/index.js diff --git a/examples/nexty/package.json b/examples/nexty/package.json new file mode 100644 index 000000000..da4cc2bc1 --- /dev/null +++ b/examples/nexty/package.json @@ -0,0 +1,29 @@ +{ + "name": "nexty", + "version": "1.0.0", + "description": "", + "framework": { + "router": { + "dir": "pages", + "extensions": [ + ".js", + ".ts", + ".tsx" + ] + }, + "development": { + "client": "framework.client.development.tsx", + "server": "framework.server.development.tsx" + }, + "production": { + "client": "framework.client.production.tsx", + "server": "framework.server.production.tsx" + } + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": {} +} diff --git a/src/api/demo/schema.js b/src/api/demo/schema.js index 21509e3d6..01ec08357 100644 --- a/src/api/demo/schema.js +++ b/src/api/demo/schema.js @@ -1,78 +1,78 @@ const Loader = { - "1": 1, - "2": 2, - "3": 3, - "4": 4, - "5": 5, - "6": 6, - "7": 7, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7, jsx: 1, js: 2, ts: 3, tsx: 4, css: 5, file: 6, - json: 7 + json: 7, }; const LoaderKeys = { - "1": "jsx", - "2": "js", - "3": "ts", - "4": "tsx", - "5": "css", - "6": "file", - "7": "json", + 1: "jsx", + 2: "js", + 3: "ts", + 4: "tsx", + 5: "css", + 6: "file", + 7: "json", jsx: "jsx", js: "js", ts: "ts", tsx: "tsx", css: "css", file: "file", - json: "json" + json: "json", }; const ResolveMode = { - "1": 1, - "2": 2, - "3": 3, - "4": 4, + 1: 1, + 2: 2, + 3: 3, + 4: 4, disable: 1, lazy: 2, dev: 3, - bundle: 4 + bundle: 4, }; const ResolveModeKeys = { - "1": "disable", - "2": "lazy", - "3": "dev", - "4": "bundle", + 1: "disable", + 2: "lazy", + 3: "dev", + 4: "bundle", disable: "disable", lazy: "lazy", dev: "dev", - bundle: "bundle" + bundle: "bundle", }; const Platform = { - "1": 1, - "2": 2, + 1: 1, + 2: 2, browser: 1, - node: 2 + node: 2, }; const PlatformKeys = { - "1": "browser", - "2": "node", + 1: "browser", + 2: "node", browser: "browser", - node: "node" + node: "node", }; const JSXRuntime = { - "1": 1, - "2": 2, + 1: 1, + 2: 2, automatic: 1, - classic: 2 + classic: 2, }; const JSXRuntimeKeys = { - "1": "automatic", - "2": "classic", + 1: "automatic", + 2: "classic", automatic: "automatic", - classic: "classic" + classic: "classic", }; function decodeJSX(bb) { var result = {}; @@ -86,38 +86,29 @@ function decodeJSX(bb) { } function encodeJSX(message, bb) { var value = message["factory"]; - if (value != null) - bb.writeString(value); - else - throw new Error("Missing required field \"factory\""); + if (value != null) bb.writeString(value); + else throw new Error('Missing required field "factory"'); var value = message["runtime"]; if (value != null) { var encoded = JSXRuntime[value]; if (encoded === undefined) - throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"JSXRuntime\""); + throw new Error( + "Invalid value " + JSON.stringify(value) + ' for enum "JSXRuntime"' + ); bb.writeByte(encoded); - } else - throw new Error("Missing required field \"runtime\""); + } else throw new Error('Missing required field "runtime"'); var value = message["fragment"]; - if (value != null) - bb.writeString(value); - else - throw new Error("Missing required field \"fragment\""); + if (value != null) bb.writeString(value); + else throw new Error('Missing required field "fragment"'); var value = message["development"]; - if (value != null) - bb.writeByte(value); - else - throw new Error("Missing required field \"development\""); + if (value != null) bb.writeByte(value); + else throw new Error('Missing required field "development"'); var value = message["import_source"]; - if (value != null) - bb.writeString(value); - else - throw new Error("Missing required field \"import_source\""); + if (value != null) bb.writeString(value); + else throw new Error('Missing required field "import_source"'); var value = message["react_fast_refresh"]; - if (value != null) - bb.writeByte(value); - else - throw new Error("Missing required field \"react_fast_refresh\""); + if (value != null) bb.writeByte(value); + else throw new Error('Missing required field "react_fast_refresh"'); } function decodeTransformOptions(bb) { var result = {}; @@ -135,67 +126,59 @@ function decodeTransformOptions(bb) { result["resolve"] = ResolveMode[bb.readByte()]; break; case 4: - result["public_url"] = bb.readString(); + result["origin"] = bb.readString(); break; case 5: result["absolute_working_dir"] = bb.readString(); break; case 6: var length = bb.readVarUint(); - var values = result["define_keys"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = bb.readString(); + var values = (result["define_keys"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = bb.readString(); break; case 7: var length = bb.readVarUint(); - var values = result["define_values"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = bb.readString(); + var values = (result["define_values"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = bb.readString(); break; case 8: result["preserve_symlinks"] = !!bb.readByte(); break; case 9: var length = bb.readVarUint(); - var values = result["entry_points"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = bb.readString(); + var values = (result["entry_points"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = bb.readString(); break; case 10: result["write"] = !!bb.readByte(); break; case 11: var length = bb.readVarUint(); - var values = result["inject"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = bb.readString(); + var values = (result["inject"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = bb.readString(); break; case 12: result["output_dir"] = bb.readString(); break; case 13: var length = bb.readVarUint(); - var values = result["external"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = bb.readString(); + var values = (result["external"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = bb.readString(); break; case 14: var length = bb.readVarUint(); - var values = result["loader_keys"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = bb.readString(); + var values = (result["loader_keys"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = bb.readString(); break; case 15: var length = bb.readVarUint(); - var values = result["loader_values"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = Loader[bb.readByte()]; + var values = (result["loader_values"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = Loader[bb.readByte()]; break; case 16: var length = bb.readVarUint(); - var values = result["main_fields"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = bb.readString(); + var values = (result["main_fields"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = bb.readString(); break; case 17: result["platform"] = Platform[bb.readByte()]; @@ -205,9 +188,8 @@ function decodeTransformOptions(bb) { break; case 19: var length = bb.readVarUint(); - var values = result["extension_order"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = bb.readString(); + var values = (result["extension_order"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = bb.readString(); break; case 20: result["public_dir"] = bb.readString(); @@ -232,10 +214,12 @@ function encodeTransformOptions(message, bb) { bb.writeByte(3); var encoded = ResolveMode[value]; if (encoded === undefined) - throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"ResolveMode\""); + throw new Error( + "Invalid value " + JSON.stringify(value) + ' for enum "ResolveMode"' + ); bb.writeByte(encoded); } - var value = message["public_url"]; + var value = message["origin"]; if (value != null) { bb.writeByte(4); bb.writeString(value); @@ -248,9 +232,10 @@ function encodeTransformOptions(message, bb) { var value = message["define_keys"]; if (value != null) { bb.writeByte(6); - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; bb.writeString(value); } @@ -258,9 +243,10 @@ function encodeTransformOptions(message, bb) { var value = message["define_values"]; if (value != null) { bb.writeByte(7); - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; bb.writeString(value); } @@ -273,9 +259,10 @@ function encodeTransformOptions(message, bb) { var value = message["entry_points"]; if (value != null) { bb.writeByte(9); - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; bb.writeString(value); } @@ -288,9 +275,10 @@ function encodeTransformOptions(message, bb) { var value = message["inject"]; if (value != null) { bb.writeByte(11); - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; bb.writeString(value); } @@ -303,9 +291,10 @@ function encodeTransformOptions(message, bb) { var value = message["external"]; if (value != null) { bb.writeByte(13); - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; bb.writeString(value); } @@ -313,9 +302,10 @@ function encodeTransformOptions(message, bb) { var value = message["loader_keys"]; if (value != null) { bb.writeByte(14); - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; bb.writeString(value); } @@ -323,22 +313,26 @@ function encodeTransformOptions(message, bb) { var value = message["loader_values"]; if (value != null) { bb.writeByte(15); - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; var encoded = Loader[value]; if (encoded === undefined) - throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"Loader\""); + throw new Error( + "Invalid value " + JSON.stringify(value) + ' for enum "Loader"' + ); bb.writeByte(encoded); } } var value = message["main_fields"]; if (value != null) { bb.writeByte(16); - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; bb.writeString(value); } @@ -348,7 +342,9 @@ function encodeTransformOptions(message, bb) { bb.writeByte(17); var encoded = Platform[value]; if (encoded === undefined) - throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"Platform\""); + throw new Error( + "Invalid value " + JSON.stringify(value) + ' for enum "Platform"' + ); bb.writeByte(encoded); } var value = message["serve"]; @@ -359,9 +355,10 @@ function encodeTransformOptions(message, bb) { var value = message["extension_order"]; if (value != null) { bb.writeByte(19); - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; bb.writeString(value); } @@ -382,20 +379,14 @@ function decodeFileHandle(bb) { } function encodeFileHandle(message, bb) { var value = message["path"]; - if (value != null) - bb.writeString(value); - else - throw new Error("Missing required field \"path\""); + if (value != null) bb.writeString(value); + else throw new Error('Missing required field "path"'); var value = message["size"]; - if (value != null) - bb.writeVarUint(value); - else - throw new Error("Missing required field \"size\""); + if (value != null) bb.writeVarUint(value); + else throw new Error('Missing required field "size"'); var value = message["fd"]; - if (value != null) - bb.writeVarUint(value); - else - throw new Error("Missing required field \"fd\""); + if (value != null) bb.writeVarUint(value); + else throw new Error('Missing required field "fd"'); } function decodeTransform(bb) { var result = {}; @@ -443,7 +434,9 @@ function encodeTransform(message, bb) { bb.writeByte(4); var encoded = Loader[value]; if (encoded === undefined) - throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"Loader\""); + throw new Error( + "Invalid value " + JSON.stringify(value) + ' for enum "Loader"' + ); bb.writeByte(encoded); } var value = message["options"]; @@ -454,16 +447,16 @@ function encodeTransform(message, bb) { bb.writeByte(0); } const TransformResponseStatus = { - "1": 1, - "2": 2, + 1: 1, + 2: 2, success: 1, - fail: 2 + fail: 2, }; const TransformResponseStatusKeys = { - "1": "success", - "2": "fail", + 1: "success", + 2: "fail", success: "success", - fail: "fail" + fail: "fail", }; function decodeOutputFile(bb) { var result = {}; @@ -473,27 +466,21 @@ function decodeOutputFile(bb) { } function encodeOutputFile(message, bb) { var value = message["data"]; - if (value != null) - bb.writeByteArray(value); - else - throw new Error("Missing required field \"data\""); + if (value != null) bb.writeByteArray(value); + else throw new Error('Missing required field "data"'); var value = message["path"]; - if (value != null) - bb.writeString(value); - else - throw new Error("Missing required field \"path\""); + if (value != null) bb.writeString(value); + else throw new Error('Missing required field "path"'); } function decodeTransformResponse(bb) { var result = {}; result["status"] = TransformResponseStatus[bb.readVarUint()]; var length = bb.readVarUint(); - var values = result["files"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = decodeOutputFile(bb); + var values = (result["files"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = decodeOutputFile(bb); var length = bb.readVarUint(); - var values = result["errors"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = decodeMessage(bb); + var values = (result["errors"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = decodeMessage(bb); return result; } function encodeTransformResponse(message, bb) { @@ -501,50 +488,53 @@ function encodeTransformResponse(message, bb) { if (value != null) { var encoded = TransformResponseStatus[value]; if (encoded === undefined) - throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"TransformResponseStatus\""); + throw new Error( + "Invalid value " + + JSON.stringify(value) + + ' for enum "TransformResponseStatus"' + ); bb.writeVarUint(encoded); - } else - throw new Error("Missing required field \"status\""); + } else throw new Error('Missing required field "status"'); var value = message["files"]; if (value != null) { - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; encodeOutputFile(value, bb); } - } else - throw new Error("Missing required field \"files\""); + } else throw new Error('Missing required field "files"'); var value = message["errors"]; if (value != null) { - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; encodeMessage(value, bb); } - } else - throw new Error("Missing required field \"errors\""); + } else throw new Error('Missing required field "errors"'); } const MessageKind = { - "1": 1, - "2": 2, - "3": 3, - "4": 4, + 1: 1, + 2: 2, + 3: 3, + 4: 4, err: 1, warn: 2, note: 3, - debug: 4 + debug: 4, }; const MessageKindKeys = { - "1": "err", - "2": "warn", - "3": "note", - "4": "debug", + 1: "err", + 2: "warn", + 3: "note", + 4: "debug", err: "err", warn: "warn", note: "note", - debug: "debug" + debug: "debug", }; function decodeLocation(bb) { var result = {}; @@ -559,40 +549,26 @@ function decodeLocation(bb) { } function encodeLocation(message, bb) { var value = message["file"]; - if (value != null) - bb.writeString(value); - else - throw new Error("Missing required field \"file\""); + if (value != null) bb.writeString(value); + else throw new Error('Missing required field "file"'); var value = message["namespace"]; - if (value != null) - bb.writeString(value); - else - throw new Error("Missing required field \"namespace\""); + if (value != null) bb.writeString(value); + else throw new Error('Missing required field "namespace"'); var value = message["line"]; - if (value != null) - bb.writeInt32(value); - else - throw new Error("Missing required field \"line\""); + if (value != null) bb.writeInt32(value); + else throw new Error('Missing required field "line"'); var value = message["column"]; - if (value != null) - bb.writeInt32(value); - else - throw new Error("Missing required field \"column\""); + if (value != null) bb.writeInt32(value); + else throw new Error('Missing required field "column"'); var value = message["line_text"]; - if (value != null) - bb.writeString(value); - else - throw new Error("Missing required field \"line_text\""); + if (value != null) bb.writeString(value); + else throw new Error('Missing required field "line_text"'); var value = message["suggestion"]; - if (value != null) - bb.writeString(value); - else - throw new Error("Missing required field \"suggestion\""); + if (value != null) bb.writeString(value); + else throw new Error('Missing required field "suggestion"'); var value = message["offset"]; - if (value != null) - bb.writeVarUint(value); - else - throw new Error("Missing required field \"offset\""); + if (value != null) bb.writeVarUint(value); + else throw new Error('Missing required field "offset"'); } function decodeMessageData(bb) { var result = {}; @@ -628,9 +604,8 @@ function decodeMessage(bb) { result["kind"] = MessageKind[bb.readVarUint()]; result["data"] = decodeMessageData(bb); var length = bb.readVarUint(); - var values = result["notes"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = decodeMessageData(bb); + var values = (result["notes"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = decodeMessageData(bb); return result; } function encodeMessage(message, bb) { @@ -638,88 +613,82 @@ function encodeMessage(message, bb) { if (value != null) { var encoded = MessageKind[value]; if (encoded === undefined) - throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"MessageKind\""); + throw new Error( + "Invalid value " + JSON.stringify(value) + ' for enum "MessageKind"' + ); bb.writeVarUint(encoded); - } else - throw new Error("Missing required field \"kind\""); + } else throw new Error('Missing required field "kind"'); var value = message["data"]; - if (value != null) - encodeMessageData(value, bb); - else - throw new Error("Missing required field \"data\""); + if (value != null) encodeMessageData(value, bb); + else throw new Error('Missing required field "data"'); var value = message["notes"]; if (value != null) { - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; encodeMessageData(value, bb); } - } else - throw new Error("Missing required field \"notes\""); + } else throw new Error('Missing required field "notes"'); } function decodeLog(bb) { var result = {}; result["warnings"] = bb.readUint32(); result["errors"] = bb.readUint32(); var length = bb.readVarUint(); - var values = result["msgs"] = Array(length); - for (var i = 0;i < length; i++) - values[i] = decodeMessage(bb); + var values = (result["msgs"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = decodeMessage(bb); return result; } function encodeLog(message, bb) { var value = message["warnings"]; - if (value != null) - bb.writeUint32(value); - else - throw new Error("Missing required field \"warnings\""); + if (value != null) bb.writeUint32(value); + else throw new Error('Missing required field "warnings"'); var value = message["errors"]; - if (value != null) - bb.writeUint32(value); - else - throw new Error("Missing required field \"errors\""); + if (value != null) bb.writeUint32(value); + else throw new Error('Missing required field "errors"'); var value = message["msgs"]; if (value != null) { - var values = value, n = values.length; + var values = value, + n = values.length; bb.writeVarUint(n); - for (var i = 0;i < n; i++) { + for (var i = 0; i < n; i++) { value = values[i]; encodeMessage(value, bb); } - } else - throw new Error("Missing required field \"msgs\""); + } else throw new Error('Missing required field "msgs"'); } -export {Loader}; -export {LoaderKeys}; -export {ResolveMode}; -export {ResolveModeKeys}; -export {Platform}; -export {PlatformKeys}; -export {JSXRuntime}; -export {JSXRuntimeKeys}; -export {decodeJSX}; -export {encodeJSX}; -export {decodeTransformOptions}; -export {encodeTransformOptions}; -export {decodeFileHandle}; -export {encodeFileHandle}; -export {decodeTransform}; -export {encodeTransform}; -export {TransformResponseStatus}; -export {TransformResponseStatusKeys}; -export {decodeOutputFile}; -export {encodeOutputFile}; -export {decodeTransformResponse}; -export {encodeTransformResponse}; -export {MessageKind}; -export {MessageKindKeys}; -export {decodeLocation}; -export {encodeLocation}; -export {decodeMessageData}; -export {encodeMessageData}; -export {decodeMessage}; -export {encodeMessage}; -export {decodeLog}; -export {encodeLog}; +export { Loader }; +export { LoaderKeys }; +export { ResolveMode }; +export { ResolveModeKeys }; +export { Platform }; +export { PlatformKeys }; +export { JSXRuntime }; +export { JSXRuntimeKeys }; +export { decodeJSX }; +export { encodeJSX }; +export { decodeTransformOptions }; +export { encodeTransformOptions }; +export { decodeFileHandle }; +export { encodeFileHandle }; +export { decodeTransform }; +export { encodeTransform }; +export { TransformResponseStatus }; +export { TransformResponseStatusKeys }; +export { decodeOutputFile }; +export { encodeOutputFile }; +export { decodeTransformResponse }; +export { encodeTransformResponse }; +export { MessageKind }; +export { MessageKindKeys }; +export { decodeLocation }; +export { encodeLocation }; +export { decodeMessageData }; +export { encodeMessageData }; +export { decodeMessage }; +export { encodeMessage }; +export { decodeLog }; +export { encodeLog }; diff --git a/src/api/schema.d.ts b/src/api/schema.d.ts index c809ec181..9d495e93a 100644 --- a/src/api/schema.d.ts +++ b/src/api/schema.d.ts @@ -210,6 +210,8 @@ type uint32 = number; export interface JavascriptBundleContainer { bundle_format_version?: uint32; bundle?: JavascriptBundle; + framework?: LoadedFramework; + routes?: LoadedRouteConfig; code_length?: uint32; } @@ -235,7 +237,22 @@ type uint32 = number; } export interface FrameworkConfig { - entry_point?: string; + package?: string; + client?: string; + server?: string; + development?: boolean; + } + + export interface LoadedFramework { + entry_point: string; + package: string; + development: boolean; + client: boolean; + } + + export interface LoadedRouteConfig { + dir: string; + extensions: string[]; } export interface RouteConfig { @@ -247,7 +264,7 @@ type uint32 = number; jsx?: JSX; tsconfig_override?: string; resolve?: ResolveMode; - public_url?: string; + origin?: string; absolute_working_dir?: string; define?: StringMap; preserve_symlinks?: boolean; @@ -265,6 +282,7 @@ type uint32 = number; only_scan_dependencies?: ScanDependencyMode; generate_node_module_bundle?: boolean; node_modules_bundle_path?: string; + node_modules_bundle_path_server?: string; framework?: FrameworkConfig; router?: RouteConfig; } @@ -420,6 +438,10 @@ type uint32 = number; export declare function decodeLoaderMap(buffer: ByteBuffer): LoaderMap; export declare function encodeFrameworkConfig(message: FrameworkConfig, bb: ByteBuffer): void; export declare function decodeFrameworkConfig(buffer: ByteBuffer): FrameworkConfig; + export declare function encodeLoadedFramework(message: LoadedFramework, bb: ByteBuffer): void; + export declare function decodeLoadedFramework(buffer: ByteBuffer): LoadedFramework; + export declare function encodeLoadedRouteConfig(message: LoadedRouteConfig, bb: ByteBuffer): void; + export declare function decodeLoadedRouteConfig(buffer: ByteBuffer): LoadedRouteConfig; export declare function encodeRouteConfig(message: RouteConfig, bb: ByteBuffer): void; export declare function decodeRouteConfig(buffer: ByteBuffer): RouteConfig; export declare function encodeTransformOptions(message: TransformOptions, bb: ByteBuffer): void; diff --git a/src/api/schema.js b/src/api/schema.js index 947e3d9a8..357692898 100644 --- a/src/api/schema.js +++ b/src/api/schema.js @@ -362,6 +362,14 @@ function decodeJavascriptBundleContainer(bb) { break; case 3: + result["framework"] = decodeLoadedFramework(bb); + break; + + case 4: + result["routes"] = decodeLoadedRouteConfig(bb); + break; + + case 5: result["code_length"] = bb.readUint32(); break; @@ -385,9 +393,21 @@ function encodeJavascriptBundleContainer(message, bb) { encodeJavascriptBundle(value, bb); } - var value = message["code_length"]; + var value = message["framework"]; if (value != null) { bb.writeByte(3); + encodeLoadedFramework(value, bb); + } + + var value = message["routes"]; + if (value != null) { + bb.writeByte(4); + encodeLoadedRouteConfig(value, bb); + } + + var value = message["code_length"]; + if (value != null) { + bb.writeByte(5); bb.writeUint32(value); } bb.writeByte(0); @@ -578,7 +598,19 @@ function decodeFrameworkConfig(bb) { return result; case 1: - result["entry_point"] = bb.readString(); + result["package"] = bb.readString(); + break; + + case 2: + result["client"] = bb.readString(); + break; + + case 3: + result["server"] = bb.readString(); + break; + + case 4: + result["development"] = !!bb.readByte(); break; default: @@ -589,15 +621,108 @@ function decodeFrameworkConfig(bb) { function encodeFrameworkConfig(message, bb) { - var value = message["entry_point"]; + var value = message["package"]; if (value != null) { bb.writeByte(1); bb.writeString(value); } + + var value = message["client"]; + if (value != null) { + bb.writeByte(2); + bb.writeString(value); + } + + var value = message["server"]; + if (value != null) { + bb.writeByte(3); + bb.writeString(value); + } + + var value = message["development"]; + if (value != null) { + bb.writeByte(4); + bb.writeByte(value); + } bb.writeByte(0); } +function decodeLoadedFramework(bb) { + var result = {}; + + result["entry_point"] = bb.readString(); + result["package"] = bb.readString(); + result["development"] = !!bb.readByte(); + result["client"] = !!bb.readByte(); + return result; +} + +function encodeLoadedFramework(message, bb) { + + var value = message["entry_point"]; + if (value != null) { + bb.writeString(value); + } else { + throw new Error("Missing required field \"entry_point\""); + } + + var value = message["package"]; + if (value != null) { + bb.writeString(value); + } else { + throw new Error("Missing required field \"package\""); + } + + var value = message["development"]; + if (value != null) { + bb.writeByte(value); + } else { + throw new Error("Missing required field \"development\""); + } + + var value = message["client"]; + if (value != null) { + bb.writeByte(value); + } else { + throw new Error("Missing required field \"client\""); + } + +} + +function decodeLoadedRouteConfig(bb) { + var result = {}; + + result["dir"] = bb.readString(); + var length = bb.readVarUint(); + var values = result["extensions"] = Array(length); + for (var i = 0; i < length; i++) values[i] = bb.readString(); + return result; +} + +function encodeLoadedRouteConfig(message, bb) { + + var value = message["dir"]; + if (value != null) { + bb.writeString(value); + } else { + throw new Error("Missing required field \"dir\""); + } + + var value = message["extensions"]; + if (value != null) { + var values = value, n = values.length; + bb.writeVarUint(n); + for (var i = 0; i < n; i++) { + value = values[i]; + bb.writeString(value); + } + } else { + throw new Error("Missing required field \"extensions\""); + } + +} + function decodeRouteConfig(bb) { var result = {}; @@ -665,7 +790,7 @@ function decodeTransformOptions(bb) { break; case 4: - result["public_url"] = bb.readString(); + result["origin"] = bb.readString(); break; case 5: @@ -747,10 +872,14 @@ function decodeTransformOptions(bb) { break; case 22: - result["framework"] = decodeFrameworkConfig(bb); + result["node_modules_bundle_path_server"] = bb.readString(); break; case 23: + result["framework"] = decodeFrameworkConfig(bb); + break; + + case 24: result["router"] = decodeRouteConfig(bb); break; @@ -782,7 +911,7 @@ if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) bb.writeByte(encoded); } - var value = message["public_url"]; + var value = message["origin"]; if (value != null) { bb.writeByte(4); bb.writeString(value); @@ -919,15 +1048,21 @@ bb.writeByte(encoded); bb.writeString(value); } - var value = message["framework"]; + var value = message["node_modules_bundle_path_server"]; if (value != null) { bb.writeByte(22); + bb.writeString(value); + } + + var value = message["framework"]; + if (value != null) { + bb.writeByte(23); encodeFrameworkConfig(value, bb); } var value = message["router"]; if (value != null) { - bb.writeByte(23); + bb.writeByte(24); encodeRouteConfig(value, bb); } bb.writeByte(0); @@ -1876,6 +2011,10 @@ export { decodeLoaderMap } export { encodeLoaderMap } export { decodeFrameworkConfig } export { encodeFrameworkConfig } +export { decodeLoadedFramework } +export { encodeLoadedFramework } +export { decodeLoadedRouteConfig } +export { encodeLoadedRouteConfig } export { decodeRouteConfig } export { encodeRouteConfig } export { decodeTransformOptions } diff --git a/src/api/schema.peechy b/src/api/schema.peechy index e558d1055..524d3c190 100644 --- a/src/api/schema.peechy +++ b/src/api/schema.peechy @@ -96,8 +96,11 @@ message JavascriptBundleContainer { JavascriptBundle bundle = 2; + LoadedFramework framework = 3; + LoadedRouteConfig routes = 4; + // Don't technically need to store this, but it may be helpful as a sanity check - uint32 code_length = 3; + uint32 code_length = 5; } smol ScanDependencyMode { @@ -133,7 +136,22 @@ struct LoaderMap { } message FrameworkConfig { - string entry_point = 1; + string package = 1; + string client = 2; + string server = 3; + bool development = 4; +} + +struct LoadedFramework { + string entry_point; + string package; + bool development; + bool client; +} + +struct LoadedRouteConfig { + string dir; + string[] extensions; } message RouteConfig { @@ -146,7 +164,7 @@ message TransformOptions { string tsconfig_override = 2; ResolveMode resolve = 3; - string public_url = 4; + string origin = 4; string absolute_working_dir = 5; StringMap define = 6; @@ -177,9 +195,10 @@ message TransformOptions { bool generate_node_module_bundle = 20; string node_modules_bundle_path = 21; + string node_modules_bundle_path_server = 22; - FrameworkConfig framework = 22; - RouteConfig router = 23; + FrameworkConfig framework = 23; + RouteConfig router = 24; } struct FileHandle { diff --git a/src/api/schema.zig b/src/api/schema.zig index 02125997e..380bbaf23 100644 --- a/src/api/schema.zig +++ b/src/api/schema.zig @@ -1,4 +1,3 @@ - const std = @import("std"); pub const Reader = struct { @@ -282,1583 +281,1597 @@ pub fn Writer(comptime WritableStream: type) type { pub const ByteWriter = Writer(*std.io.FixedBufferStream([]u8)); pub const FileWriter = Writer(std.fs.File); +pub const Api = struct { + pub const Loader = enum(u8) { + _none, + /// jsx + jsx, + /// js + js, + /// ts + ts, -pub const Api = struct { - -pub const Loader = enum(u8) { - -_none, - /// jsx - jsx, - - /// js - js, - - /// ts - ts, - - /// tsx - tsx, - - /// css - css, - - /// file - file, - - /// json - json, - -_, - - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - - -}; - -pub const ResolveMode = enum(u8) { - -_none, - /// disable - disable, - - /// lazy - lazy, - - /// dev - dev, - - /// bundle - bundle, - -_, - - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - - -}; - -pub const Platform = enum(u8) { + /// tsx + tsx, -_none, - /// browser - browser, + /// css + css, - /// node - node, + /// file + file, - /// speedy - speedy, + /// json + json, -_, + _, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - - -}; - -pub const JsxRuntime = enum(u8) { - -_none, - /// automatic - automatic, - - /// classic - classic, - -_, - - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - - -}; + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; -pub const Jsx = struct { -/// factory -factory: []const u8, + pub const ResolveMode = enum(u8) { + _none, + /// disable + disable, -/// runtime -runtime: JsxRuntime, + /// lazy + lazy, -/// fragment -fragment: []const u8, + /// dev + dev, -/// development -development: bool = false, + /// bundle + bundle, -/// import_source -import_source: []const u8, + _, -/// react_fast_refresh -react_fast_refresh: bool = false, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; + pub const Platform = enum(u8) { + _none, + /// browser + browser, -pub fn decode(reader: anytype) anyerror!Jsx { - var this = std.mem.zeroes(Jsx); + /// node + node, - this.factory = try reader.readValue([]const u8); - this.runtime = try reader.readValue(JsxRuntime); - this.fragment = try reader.readValue([]const u8); - this.development = try reader.readValue(bool); - this.import_source = try reader.readValue([]const u8); - this.react_fast_refresh = try reader.readValue(bool); - return this; -} + /// speedy + speedy, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.factory); - try writer.writeEnum(this.runtime); - try writer.writeValue(this.fragment); - try writer.writeInt(@intCast(u8, @boolToInt(this.development))); - try writer.writeValue(this.import_source); - try writer.writeInt(@intCast(u8, @boolToInt(this.react_fast_refresh))); -} + _, -}; + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; -pub const StringPointer = packed struct { -/// offset -offset: u32 = 0, + pub const JsxRuntime = enum(u8) { + _none, + /// automatic + automatic, -/// length -length: u32 = 0, + /// classic + classic, + _, -pub fn decode(reader: anytype) anyerror!StringPointer { - var this = std.mem.zeroes(StringPointer); + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; - this.offset = try reader.readValue(u32); - this.length = try reader.readValue(u32); - return this; -} + pub const Jsx = struct { + /// factory + factory: []const u8, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.offset); - try writer.writeInt(this.length); -} + /// runtime + runtime: JsxRuntime, -}; + /// fragment + fragment: []const u8, -pub const JavascriptBundledModule = struct { -/// path -path: StringPointer, + /// development + development: bool = false, -/// code -code: StringPointer, + /// import_source + import_source: []const u8, -/// package_id -package_id: u32 = 0, + /// react_fast_refresh + react_fast_refresh: bool = false, -/// id -id: u32 = 0, + pub fn decode(reader: anytype) anyerror!Jsx { + var this = std.mem.zeroes(Jsx); -/// path_extname_length -path_extname_length: u8 = 0, + this.factory = try reader.readValue([]const u8); + this.runtime = try reader.readValue(JsxRuntime); + this.fragment = try reader.readValue([]const u8); + this.development = try reader.readValue(bool); + this.import_source = try reader.readValue([]const u8); + this.react_fast_refresh = try reader.readValue(bool); + return this; + } + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.factory); + try writer.writeEnum(this.runtime); + try writer.writeValue(this.fragment); + try writer.writeInt(@intCast(u8, @boolToInt(this.development))); + try writer.writeValue(this.import_source); + try writer.writeInt(@intCast(u8, @boolToInt(this.react_fast_refresh))); + } + }; -pub fn decode(reader: anytype) anyerror!JavascriptBundledModule { - var this = std.mem.zeroes(JavascriptBundledModule); + pub const StringPointer = packed struct { + /// offset + offset: u32 = 0, - this.path = try reader.readValue(StringPointer); - this.code = try reader.readValue(StringPointer); - this.package_id = try reader.readValue(u32); - this.id = try reader.readValue(u32); - this.path_extname_length = try reader.readValue(u8); - return this; -} + /// length + length: u32 = 0, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.path); - try writer.writeValue(this.code); - try writer.writeInt(this.package_id); - try writer.writeInt(this.id); - try writer.writeInt(this.path_extname_length); -} + pub fn decode(reader: anytype) anyerror!StringPointer { + var this = std.mem.zeroes(StringPointer); -}; + this.offset = try reader.readValue(u32); + this.length = try reader.readValue(u32); + return this; + } -pub const JavascriptBundledPackage = struct { -/// name -name: StringPointer, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.offset); + try writer.writeInt(this.length); + } + }; -/// version -version: StringPointer, + pub const JavascriptBundledModule = struct { + /// path + path: StringPointer, -/// hash -hash: u32 = 0, + /// code + code: StringPointer, -/// modules_offset -modules_offset: u32 = 0, + /// package_id + package_id: u32 = 0, -/// modules_length -modules_length: u32 = 0, + /// id + id: u32 = 0, + /// path_extname_length + path_extname_length: u8 = 0, -pub fn decode(reader: anytype) anyerror!JavascriptBundledPackage { - var this = std.mem.zeroes(JavascriptBundledPackage); + pub fn decode(reader: anytype) anyerror!JavascriptBundledModule { + var this = std.mem.zeroes(JavascriptBundledModule); - this.name = try reader.readValue(StringPointer); - this.version = try reader.readValue(StringPointer); - this.hash = try reader.readValue(u32); - this.modules_offset = try reader.readValue(u32); - this.modules_length = try reader.readValue(u32); - return this; -} + this.path = try reader.readValue(StringPointer); + this.code = try reader.readValue(StringPointer); + this.package_id = try reader.readValue(u32); + this.id = try reader.readValue(u32); + this.path_extname_length = try reader.readValue(u8); + return this; + } -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.name); - try writer.writeValue(this.version); - try writer.writeInt(this.hash); - try writer.writeInt(this.modules_offset); - try writer.writeInt(this.modules_length); -} + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeValue(this.code); + try writer.writeInt(this.package_id); + try writer.writeInt(this.id); + try writer.writeInt(this.path_extname_length); + } + }; -}; + pub const JavascriptBundledPackage = struct { + /// name + name: StringPointer, -pub const JavascriptBundle = struct { -/// modules -modules: []const JavascriptBundledModule, + /// version + version: StringPointer, -/// packages -packages: []const JavascriptBundledPackage, + /// hash + hash: u32 = 0, -/// etag -etag: []const u8, + /// modules_offset + modules_offset: u32 = 0, -/// generated_at -generated_at: u32 = 0, + /// modules_length + modules_length: u32 = 0, -/// app_package_json_dependencies_hash -app_package_json_dependencies_hash: []const u8, + pub fn decode(reader: anytype) anyerror!JavascriptBundledPackage { + var this = std.mem.zeroes(JavascriptBundledPackage); -/// import_from_name -import_from_name: []const u8, + this.name = try reader.readValue(StringPointer); + this.version = try reader.readValue(StringPointer); + this.hash = try reader.readValue(u32); + this.modules_offset = try reader.readValue(u32); + this.modules_length = try reader.readValue(u32); + return this; + } -/// manifest_string -manifest_string: []const u8, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.name); + try writer.writeValue(this.version); + try writer.writeInt(this.hash); + try writer.writeInt(this.modules_offset); + try writer.writeInt(this.modules_length); + } + }; + pub const JavascriptBundle = struct { + /// modules + modules: []const JavascriptBundledModule, -pub fn decode(reader: anytype) anyerror!JavascriptBundle { - var this = std.mem.zeroes(JavascriptBundle); + /// packages + packages: []const JavascriptBundledPackage, - this.modules = try reader.readArray(JavascriptBundledModule); - this.packages = try reader.readArray(JavascriptBundledPackage); - this.etag = try reader.readArray(u8); - this.generated_at = try reader.readValue(u32); - this.app_package_json_dependencies_hash = try reader.readArray(u8); - this.import_from_name = try reader.readArray(u8); - this.manifest_string = try reader.readArray(u8); - return this; -} + /// etag + etag: []const u8, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(JavascriptBundledModule, this.modules); - try writer.writeArray(JavascriptBundledPackage, this.packages); - try writer.writeArray(u8, this.etag); - try writer.writeInt(this.generated_at); - try writer.writeArray(u8, this.app_package_json_dependencies_hash); - try writer.writeArray(u8, this.import_from_name); - try writer.writeArray(u8, this.manifest_string); -} + /// generated_at + generated_at: u32 = 0, -}; + /// app_package_json_dependencies_hash + app_package_json_dependencies_hash: []const u8, -pub const JavascriptBundleContainer = struct { -/// bundle_format_version -bundle_format_version: ?u32 = null, - -/// bundle -bundle: ?JavascriptBundle = null, - -/// code_length -code_length: ?u32 = null, - - -pub fn decode(reader: anytype) anyerror!JavascriptBundleContainer { - var this = std.mem.zeroes(JavascriptBundleContainer); - - while(true) { - switch (try reader.readByte()) { - 0 => { return this; }, - - 1 => { - this.bundle_format_version = try reader.readValue(u32); -}, - 2 => { - this.bundle = try reader.readValue(JavascriptBundle); -}, - 3 => { - this.code_length = try reader.readValue(u32); -}, - else => { - return error.InvalidMessage; - }, - } - } -unreachable; -} + /// import_from_name + import_from_name: []const u8, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { -if (this.bundle_format_version) |bundle_format_version| { - try writer.writeFieldID(1); - try writer.writeInt(bundle_format_version); -} -if (this.bundle) |bundle| { - try writer.writeFieldID(2); - try writer.writeValue(bundle); -} -if (this.code_length) |code_length| { - try writer.writeFieldID(3); - try writer.writeInt(code_length); -} -try writer.endMessage(); -} + /// manifest_string + manifest_string: []const u8, -}; - -pub const ScanDependencyMode = enum(u8) { + pub fn decode(reader: anytype) anyerror!JavascriptBundle { + var this = std.mem.zeroes(JavascriptBundle); -_none, - /// app - app, + this.modules = try reader.readArray(JavascriptBundledModule); + this.packages = try reader.readArray(JavascriptBundledPackage); + this.etag = try reader.readArray(u8); + this.generated_at = try reader.readValue(u32); + this.app_package_json_dependencies_hash = try reader.readArray(u8); + this.import_from_name = try reader.readArray(u8); + this.manifest_string = try reader.readArray(u8); + return this; + } - /// all - all, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(JavascriptBundledModule, this.modules); + try writer.writeArray(JavascriptBundledPackage, this.packages); + try writer.writeArray(u8, this.etag); + try writer.writeInt(this.generated_at); + try writer.writeArray(u8, this.app_package_json_dependencies_hash); + try writer.writeArray(u8, this.import_from_name); + try writer.writeArray(u8, this.manifest_string); + } + }; -_, + pub const JavascriptBundleContainer = struct { + /// bundle_format_version + bundle_format_version: ?u32 = null, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } + /// bundle + bundle: ?JavascriptBundle = null, - -}; + /// framework + framework: ?LoadedFramework = null, -pub const ModuleImportType = enum(u8) { + /// routes + routes: ?LoadedRouteConfig = null, -_none, - /// import - import, + /// code_length + code_length: ?u32 = null, - /// require - require, + pub fn decode(reader: anytype) anyerror!JavascriptBundleContainer { + var this = std.mem.zeroes(JavascriptBundleContainer); -_, + while (true) { + switch (try reader.readByte()) { + 0 => { + return this; + }, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); + 1 => { + this.bundle_format_version = try reader.readValue(u32); + }, + 2 => { + this.bundle = try reader.readValue(JavascriptBundle); + }, + 3 => { + this.framework = try reader.readValue(LoadedFramework); + }, + 4 => { + this.routes = try reader.readValue(LoadedRouteConfig); + }, + 5 => { + this.code_length = try reader.readValue(u32); + }, + else => { + return error.InvalidMessage; + }, } + } + unreachable; + } - -}; - -pub const ModuleImportRecord = struct { -/// kind -kind: ModuleImportType, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.bundle_format_version) |bundle_format_version| { + try writer.writeFieldID(1); + try writer.writeInt(bundle_format_version); + } + if (this.bundle) |bundle| { + try writer.writeFieldID(2); + try writer.writeValue(bundle); + } + if (this.framework) |framework| { + try writer.writeFieldID(3); + try writer.writeValue(framework); + } + if (this.routes) |routes| { + try writer.writeFieldID(4); + try writer.writeValue(routes); + } + if (this.code_length) |code_length| { + try writer.writeFieldID(5); + try writer.writeInt(code_length); + } + try writer.endMessage(); + } + }; -/// path -path: []const u8, + pub const ScanDependencyMode = enum(u8) { + _none, + /// app + app, -/// dynamic -dynamic: bool = false, + /// all + all, + _, -pub fn decode(reader: anytype) anyerror!ModuleImportRecord { - var this = std.mem.zeroes(ModuleImportRecord); + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; - this.kind = try reader.readValue(ModuleImportType); - this.path = try reader.readValue([]const u8); - this.dynamic = try reader.readValue(bool); - return this; -} + pub const ModuleImportType = enum(u8) { + _none, + /// import + import, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.kind); - try writer.writeValue(this.path); - try writer.writeInt(@intCast(u8, @boolToInt(this.dynamic))); -} + /// require + require, -}; + _, -pub const Module = struct { -/// path -path: []const u8, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; -/// imports -imports: []const ModuleImportRecord, + pub const ModuleImportRecord = struct { + /// kind + kind: ModuleImportType, + /// path + path: []const u8, -pub fn decode(reader: anytype) anyerror!Module { - var this = std.mem.zeroes(Module); + /// dynamic + dynamic: bool = false, - this.path = try reader.readValue([]const u8); - this.imports = try reader.readArray(ModuleImportRecord); - return this; -} + pub fn decode(reader: anytype) anyerror!ModuleImportRecord { + var this = std.mem.zeroes(ModuleImportRecord); -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.path); - try writer.writeArray(ModuleImportRecord, this.imports); -} - -}; + this.kind = try reader.readValue(ModuleImportType); + this.path = try reader.readValue([]const u8); + this.dynamic = try reader.readValue(bool); + return this; + } -pub const StringMap = struct { -/// keys -keys: []const []const u8, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.kind); + try writer.writeValue(this.path); + try writer.writeInt(@intCast(u8, @boolToInt(this.dynamic))); + } + }; -/// values -values: []const []const u8, + pub const Module = struct { + /// path + path: []const u8, + /// imports + imports: []const ModuleImportRecord, -pub fn decode(reader: anytype) anyerror!StringMap { - var this = std.mem.zeroes(StringMap); + pub fn decode(reader: anytype) anyerror!Module { + var this = std.mem.zeroes(Module); - this.keys = try reader.readArray([]const u8); - this.values = try reader.readArray([]const u8); - return this; -} + this.path = try reader.readValue([]const u8); + this.imports = try reader.readArray(ModuleImportRecord); + return this; + } -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray([]const u8, this.keys); - try writer.writeArray([]const u8, this.values); -} + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeArray(ModuleImportRecord, this.imports); + } + }; -}; + pub const StringMap = struct { + /// keys + keys: []const []const u8, -pub const LoaderMap = struct { -/// extensions -extensions: []const []const u8, + /// values + values: []const []const u8, -/// loaders -loaders: []const Loader, + pub fn decode(reader: anytype) anyerror!StringMap { + var this = std.mem.zeroes(StringMap); + this.keys = try reader.readArray([]const u8); + this.values = try reader.readArray([]const u8); + return this; + } -pub fn decode(reader: anytype) anyerror!LoaderMap { - var this = std.mem.zeroes(LoaderMap); + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray([]const u8, this.keys); + try writer.writeArray([]const u8, this.values); + } + }; - this.extensions = try reader.readArray([]const u8); - this.loaders = try reader.readArray(Loader); - return this; -} + pub const LoaderMap = struct { + /// extensions + extensions: []const []const u8, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray([]const u8, this.extensions); - try writer.writeArray(Loader, this.loaders); -} + /// loaders + loaders: []const Loader, -}; + pub fn decode(reader: anytype) anyerror!LoaderMap { + var this = std.mem.zeroes(LoaderMap); -pub const FrameworkConfig = struct { -/// entry_point -entry_point: ?[]const u8 = null, + this.extensions = try reader.readArray([]const u8); + this.loaders = try reader.readArray(Loader); + return this; + } + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray([]const u8, this.extensions); + try writer.writeArray(Loader, this.loaders); + } + }; -pub fn decode(reader: anytype) anyerror!FrameworkConfig { - var this = std.mem.zeroes(FrameworkConfig); + pub const FrameworkConfig = struct { + /// package + package: ?[]const u8 = null, - while(true) { - switch (try reader.readByte()) { - 0 => { return this; }, + /// client + client: ?[]const u8 = null, - 1 => { - this.entry_point = try reader.readValue([]const u8); -}, - else => { - return error.InvalidMessage; - }, - } - } -unreachable; -} + /// server + server: ?[]const u8 = null, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { -if (this.entry_point) |entry_point| { - try writer.writeFieldID(1); - try writer.writeValue(entry_point); -} -try writer.endMessage(); -} + /// development + development: ?bool = null, -}; + pub fn decode(reader: anytype) anyerror!FrameworkConfig { + var this = std.mem.zeroes(FrameworkConfig); -pub const RouteConfig = struct { -/// dir -dir: ?[]const u8 = null, - -/// extensions -extensions: []const []const u8, - - -pub fn decode(reader: anytype) anyerror!RouteConfig { - var this = std.mem.zeroes(RouteConfig); - - while(true) { - switch (try reader.readByte()) { - 0 => { return this; }, - - 1 => { - this.dir = try reader.readValue([]const u8); -}, - 2 => { - this.extensions = try reader.readArray([]const u8); -}, - else => { - return error.InvalidMessage; - }, - } - } -unreachable; -} + while (true) { + switch (try reader.readByte()) { + 0 => { + return this; + }, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { -if (this.dir) |dir| { - try writer.writeFieldID(1); - try writer.writeValue(dir); -} -if (this.extensions) |extensions| { - try writer.writeFieldID(2); - try writer.writeArray([]const u8, extensions); -} -try writer.endMessage(); -} + 1 => { + this.package = try reader.readValue([]const u8); + }, + 2 => { + this.client = try reader.readValue([]const u8); + }, + 3 => { + this.server = try reader.readValue([]const u8); + }, + 4 => { + this.development = try reader.readValue(bool); + }, + else => { + return error.InvalidMessage; + }, + } + } + unreachable; + } -}; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.package) |package| { + try writer.writeFieldID(1); + try writer.writeValue(package); + } + if (this.client) |client| { + try writer.writeFieldID(2); + try writer.writeValue(client); + } + if (this.server) |server| { + try writer.writeFieldID(3); + try writer.writeValue(server); + } + if (this.development) |development| { + try writer.writeFieldID(4); + try writer.writeInt(@intCast(u8, @boolToInt(development))); + } + try writer.endMessage(); + } + }; -pub const TransformOptions = struct { -/// jsx -jsx: ?Jsx = null, + pub const LoadedFramework = struct { + /// entry_point + entry_point: []const u8, -/// tsconfig_override -tsconfig_override: ?[]const u8 = null, + /// package + package: []const u8, -/// resolve -resolve: ?ResolveMode = null, + /// development + development: bool = false, -/// public_url -public_url: ?[]const u8 = null, - -/// absolute_working_dir -absolute_working_dir: ?[]const u8 = null, - -/// define -define: ?StringMap = null, - -/// preserve_symlinks -preserve_symlinks: ?bool = null, - -/// entry_points -entry_points: []const []const u8, - -/// write -write: ?bool = null, - -/// inject -inject: []const []const u8, - -/// output_dir -output_dir: ?[]const u8 = null, - -/// external -external: []const []const u8, - -/// loaders -loaders: ?LoaderMap = null, - -/// main_fields -main_fields: []const []const u8, - -/// platform -platform: ?Platform = null, - -/// serve -serve: ?bool = null, - -/// extension_order -extension_order: []const []const u8, - -/// public_dir -public_dir: ?[]const u8 = null, - -/// only_scan_dependencies -only_scan_dependencies: ?ScanDependencyMode = null, - -/// generate_node_module_bundle -generate_node_module_bundle: ?bool = null, - -/// node_modules_bundle_path -node_modules_bundle_path: ?[]const u8 = null, - -/// framework -framework: ?FrameworkConfig = null, - -/// router -router: ?RouteConfig = null, - - -pub fn decode(reader: anytype) anyerror!TransformOptions { - var this = std.mem.zeroes(TransformOptions); - - while(true) { - switch (try reader.readByte()) { - 0 => { return this; }, - - 1 => { - this.jsx = try reader.readValue(Jsx); -}, - 2 => { - this.tsconfig_override = try reader.readValue([]const u8); -}, - 3 => { - this.resolve = try reader.readValue(ResolveMode); -}, - 4 => { - this.public_url = try reader.readValue([]const u8); -}, - 5 => { - this.absolute_working_dir = try reader.readValue([]const u8); -}, - 6 => { - this.define = try reader.readValue(StringMap); -}, - 7 => { - this.preserve_symlinks = try reader.readValue(bool); -}, - 8 => { - this.entry_points = try reader.readArray([]const u8); -}, - 9 => { - this.write = try reader.readValue(bool); -}, - 10 => { - this.inject = try reader.readArray([]const u8); -}, - 11 => { - this.output_dir = try reader.readValue([]const u8); -}, - 12 => { - this.external = try reader.readArray([]const u8); -}, - 13 => { - this.loaders = try reader.readValue(LoaderMap); -}, - 14 => { - this.main_fields = try reader.readArray([]const u8); -}, - 15 => { - this.platform = try reader.readValue(Platform); -}, - 16 => { - this.serve = try reader.readValue(bool); -}, - 17 => { - this.extension_order = try reader.readArray([]const u8); -}, - 18 => { - this.public_dir = try reader.readValue([]const u8); -}, - 19 => { - this.only_scan_dependencies = try reader.readValue(ScanDependencyMode); -}, - 20 => { - this.generate_node_module_bundle = try reader.readValue(bool); -}, - 21 => { - this.node_modules_bundle_path = try reader.readValue([]const u8); -}, - 22 => { - this.framework = try reader.readValue(FrameworkConfig); -}, - 23 => { - this.router = try reader.readValue(RouteConfig); -}, - else => { - return error.InvalidMessage; - }, - } - } -unreachable; -} + /// client + client: bool = false, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { -if (this.jsx) |jsx| { - try writer.writeFieldID(1); - try writer.writeValue(jsx); -} -if (this.tsconfig_override) |tsconfig_override| { - try writer.writeFieldID(2); - try writer.writeValue(tsconfig_override); -} -if (this.resolve) |resolve| { - try writer.writeFieldID(3); - try writer.writeEnum(resolve); -} -if (this.public_url) |public_url| { - try writer.writeFieldID(4); - try writer.writeValue(public_url); -} -if (this.absolute_working_dir) |absolute_working_dir| { - try writer.writeFieldID(5); - try writer.writeValue(absolute_working_dir); -} -if (this.define) |define| { - try writer.writeFieldID(6); - try writer.writeValue(define); -} -if (this.preserve_symlinks) |preserve_symlinks| { - try writer.writeFieldID(7); - try writer.writeInt(@intCast(u8, @boolToInt(preserve_symlinks))); -} -if (this.entry_points) |entry_points| { - try writer.writeFieldID(8); - try writer.writeArray([]const u8, entry_points); -} -if (this.write) |write| { - try writer.writeFieldID(9); - try writer.writeInt(@intCast(u8, @boolToInt(write))); -} -if (this.inject) |inject| { - try writer.writeFieldID(10); - try writer.writeArray([]const u8, inject); -} -if (this.output_dir) |output_dir| { - try writer.writeFieldID(11); - try writer.writeValue(output_dir); -} -if (this.external) |external| { - try writer.writeFieldID(12); - try writer.writeArray([]const u8, external); -} -if (this.loaders) |loaders| { - try writer.writeFieldID(13); - try writer.writeValue(loaders); -} -if (this.main_fields) |main_fields| { - try writer.writeFieldID(14); - try writer.writeArray([]const u8, main_fields); -} -if (this.platform) |platform| { - try writer.writeFieldID(15); - try writer.writeEnum(platform); -} -if (this.serve) |serve| { - try writer.writeFieldID(16); - try writer.writeInt(@intCast(u8, @boolToInt(serve))); -} -if (this.extension_order) |extension_order| { - try writer.writeFieldID(17); - try writer.writeArray([]const u8, extension_order); -} -if (this.public_dir) |public_dir| { - try writer.writeFieldID(18); - try writer.writeValue(public_dir); -} -if (this.only_scan_dependencies) |only_scan_dependencies| { - try writer.writeFieldID(19); - try writer.writeEnum(only_scan_dependencies); -} -if (this.generate_node_module_bundle) |generate_node_module_bundle| { - try writer.writeFieldID(20); - try writer.writeInt(@intCast(u8, @boolToInt(generate_node_module_bundle))); -} -if (this.node_modules_bundle_path) |node_modules_bundle_path| { - try writer.writeFieldID(21); - try writer.writeValue(node_modules_bundle_path); -} -if (this.framework) |framework| { - try writer.writeFieldID(22); - try writer.writeValue(framework); -} -if (this.router) |router| { - try writer.writeFieldID(23); - try writer.writeValue(router); -} -try writer.endMessage(); -} + pub fn decode(reader: anytype) anyerror!LoadedFramework { + var this = std.mem.zeroes(LoadedFramework); -}; + this.entry_point = try reader.readValue([]const u8); + this.package = try reader.readValue([]const u8); + this.development = try reader.readValue(bool); + this.client = try reader.readValue(bool); + return this; + } -pub const FileHandle = struct { -/// path -path: []const u8, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.entry_point); + try writer.writeValue(this.package); + try writer.writeInt(@intCast(u8, @boolToInt(this.development))); + try writer.writeInt(@intCast(u8, @boolToInt(this.client))); + } + }; -/// size -size: u32 = 0, + pub const LoadedRouteConfig = struct { + /// dir + dir: []const u8, -/// fd -fd: u32 = 0, + /// extensions + extensions: []const []const u8, + pub fn decode(reader: anytype) anyerror!LoadedRouteConfig { + var this = std.mem.zeroes(LoadedRouteConfig); -pub fn decode(reader: anytype) anyerror!FileHandle { - var this = std.mem.zeroes(FileHandle); + this.dir = try reader.readValue([]const u8); + this.extensions = try reader.readArray([]const u8); + return this; + } - this.path = try reader.readValue([]const u8); - this.size = try reader.readValue(u32); - this.fd = try reader.readValue(u32); - return this; -} + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.dir); + try writer.writeArray([]const u8, this.extensions); + } + }; -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.path); - try writer.writeInt(this.size); - try writer.writeInt(this.fd); -} + pub const RouteConfig = struct { + /// dir + dir: ?[]const u8 = null, -}; + /// extensions + extensions: []const []const u8, -pub const Transform = struct { -/// handle -handle: ?FileHandle = null, - -/// path -path: ?[]const u8 = null, - -/// contents -contents: []const u8, - -/// loader -loader: ?Loader = null, - -/// options -options: ?TransformOptions = null, - - -pub fn decode(reader: anytype) anyerror!Transform { - var this = std.mem.zeroes(Transform); - - while(true) { - switch (try reader.readByte()) { - 0 => { return this; }, - - 1 => { - this.handle = try reader.readValue(FileHandle); -}, - 2 => { - this.path = try reader.readValue([]const u8); -}, - 3 => { - this.contents = try reader.readArray(u8); -}, - 4 => { - this.loader = try reader.readValue(Loader); -}, - 5 => { - this.options = try reader.readValue(TransformOptions); -}, - else => { - return error.InvalidMessage; - }, - } - } -unreachable; -} + pub fn decode(reader: anytype) anyerror!RouteConfig { + var this = std.mem.zeroes(RouteConfig); -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { -if (this.handle) |handle| { - try writer.writeFieldID(1); - try writer.writeValue(handle); -} -if (this.path) |path| { - try writer.writeFieldID(2); - try writer.writeValue(path); -} -if (this.contents) |contents| { - try writer.writeFieldID(3); - try writer.writeArray(u8, contents); -} -if (this.loader) |loader| { - try writer.writeFieldID(4); - try writer.writeEnum(loader); -} -if (this.options) |options| { - try writer.writeFieldID(5); - try writer.writeValue(options); -} -try writer.endMessage(); -} + while (true) { + switch (try reader.readByte()) { + 0 => { + return this; + }, -}; + 1 => { + this.dir = try reader.readValue([]const u8); + }, + 2 => { + this.extensions = try reader.readArray([]const u8); + }, + else => { + return error.InvalidMessage; + }, + } + } + unreachable; + } -pub const TransformResponseStatus = enum(u32) { + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.dir) |dir| { + try writer.writeFieldID(1); + try writer.writeValue(dir); + } + if (this.extensions) |extensions| { + try writer.writeFieldID(2); + try writer.writeArray([]const u8, extensions); + } + try writer.endMessage(); + } + }; -_none, - /// success - success, + pub const TransformOptions = struct { + /// jsx + jsx: ?Jsx = null, - /// fail - fail, + /// tsconfig_override + tsconfig_override: ?[]const u8 = null, -_, + /// resolve + resolve: ?ResolveMode = null, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } + /// origin + origin: ?[]const u8 = null, - -}; + /// absolute_working_dir + absolute_working_dir: ?[]const u8 = null, -pub const OutputFile = struct { -/// data -data: []const u8, + /// define + define: ?StringMap = null, -/// path -path: []const u8, + /// preserve_symlinks + preserve_symlinks: ?bool = null, + /// entry_points + entry_points: []const []const u8, -pub fn decode(reader: anytype) anyerror!OutputFile { - var this = std.mem.zeroes(OutputFile); + /// write + write: ?bool = null, - this.data = try reader.readArray(u8); - this.path = try reader.readValue([]const u8); - return this; -} + /// inject + inject: []const []const u8, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(u8, this.data); - try writer.writeValue(this.path); -} + /// output_dir + output_dir: ?[]const u8 = null, -}; + /// external + external: []const []const u8, -pub const TransformResponse = struct { -/// status -status: TransformResponseStatus, + /// loaders + loaders: ?LoaderMap = null, -/// files -files: []const OutputFile, + /// main_fields + main_fields: []const []const u8, -/// errors -errors: []const Message, + /// platform + platform: ?Platform = null, + /// serve + serve: ?bool = null, -pub fn decode(reader: anytype) anyerror!TransformResponse { - var this = std.mem.zeroes(TransformResponse); + /// extension_order + extension_order: []const []const u8, - this.status = try reader.readValue(TransformResponseStatus); - this.files = try reader.readArray(OutputFile); - this.errors = try reader.readArray(Message); - return this; -} + /// public_dir + public_dir: ?[]const u8 = null, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.status); - try writer.writeArray(OutputFile, this.files); - try writer.writeArray(Message, this.errors); -} + /// only_scan_dependencies + only_scan_dependencies: ?ScanDependencyMode = null, -}; + /// generate_node_module_bundle + generate_node_module_bundle: ?bool = null, -pub const MessageKind = enum(u32) { + /// node_modules_bundle_path + node_modules_bundle_path: ?[]const u8 = null, -_none, - /// err - err, + /// node_modules_bundle_path_server + node_modules_bundle_path_server: ?[]const u8 = null, - /// warn - warn, + /// framework + framework: ?FrameworkConfig = null, - /// note - note, + /// router + router: ?RouteConfig = null, - /// debug - debug, + pub fn decode(reader: anytype) anyerror!TransformOptions { + var this = std.mem.zeroes(TransformOptions); -_, + while (true) { + switch (try reader.readByte()) { + 0 => { + return this; + }, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); + 1 => { + this.jsx = try reader.readValue(Jsx); + }, + 2 => { + this.tsconfig_override = try reader.readValue([]const u8); + }, + 3 => { + this.resolve = try reader.readValue(ResolveMode); + }, + 4 => { + this.origin = try reader.readValue([]const u8); + }, + 5 => { + this.absolute_working_dir = try reader.readValue([]const u8); + }, + 6 => { + this.define = try reader.readValue(StringMap); + }, + 7 => { + this.preserve_symlinks = try reader.readValue(bool); + }, + 8 => { + this.entry_points = try reader.readArray([]const u8); + }, + 9 => { + this.write = try reader.readValue(bool); + }, + 10 => { + this.inject = try reader.readArray([]const u8); + }, + 11 => { + this.output_dir = try reader.readValue([]const u8); + }, + 12 => { + this.external = try reader.readArray([]const u8); + }, + 13 => { + this.loaders = try reader.readValue(LoaderMap); + }, + 14 => { + this.main_fields = try reader.readArray([]const u8); + }, + 15 => { + this.platform = try reader.readValue(Platform); + }, + 16 => { + this.serve = try reader.readValue(bool); + }, + 17 => { + this.extension_order = try reader.readArray([]const u8); + }, + 18 => { + this.public_dir = try reader.readValue([]const u8); + }, + 19 => { + this.only_scan_dependencies = try reader.readValue(ScanDependencyMode); + }, + 20 => { + this.generate_node_module_bundle = try reader.readValue(bool); + }, + 21 => { + this.node_modules_bundle_path = try reader.readValue([]const u8); + }, + 22 => { + this.node_modules_bundle_path_server = try reader.readValue([]const u8); + }, + 23 => { + this.framework = try reader.readValue(FrameworkConfig); + }, + 24 => { + this.router = try reader.readValue(RouteConfig); + }, + else => { + return error.InvalidMessage; + }, } + } + unreachable; + } - -}; - -pub const Location = struct { -/// file -file: []const u8, - -/// namespace -namespace: []const u8, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.jsx) |jsx| { + try writer.writeFieldID(1); + try writer.writeValue(jsx); + } + if (this.tsconfig_override) |tsconfig_override| { + try writer.writeFieldID(2); + try writer.writeValue(tsconfig_override); + } + if (this.resolve) |resolve| { + try writer.writeFieldID(3); + try writer.writeEnum(resolve); + } + if (this.origin) |origin| { + try writer.writeFieldID(4); + try writer.writeValue(origin); + } + if (this.absolute_working_dir) |absolute_working_dir| { + try writer.writeFieldID(5); + try writer.writeValue(absolute_working_dir); + } + if (this.define) |define| { + try writer.writeFieldID(6); + try writer.writeValue(define); + } + if (this.preserve_symlinks) |preserve_symlinks| { + try writer.writeFieldID(7); + try writer.writeInt(@intCast(u8, @boolToInt(preserve_symlinks))); + } + if (this.entry_points) |entry_points| { + try writer.writeFieldID(8); + try writer.writeArray([]const u8, entry_points); + } + if (this.write) |write| { + try writer.writeFieldID(9); + try writer.writeInt(@intCast(u8, @boolToInt(write))); + } + if (this.inject) |inject| { + try writer.writeFieldID(10); + try writer.writeArray([]const u8, inject); + } + if (this.output_dir) |output_dir| { + try writer.writeFieldID(11); + try writer.writeValue(output_dir); + } + if (this.external) |external| { + try writer.writeFieldID(12); + try writer.writeArray([]const u8, external); + } + if (this.loaders) |loaders| { + try writer.writeFieldID(13); + try writer.writeValue(loaders); + } + if (this.main_fields) |main_fields| { + try writer.writeFieldID(14); + try writer.writeArray([]const u8, main_fields); + } + if (this.platform) |platform| { + try writer.writeFieldID(15); + try writer.writeEnum(platform); + } + if (this.serve) |serve| { + try writer.writeFieldID(16); + try writer.writeInt(@intCast(u8, @boolToInt(serve))); + } + if (this.extension_order) |extension_order| { + try writer.writeFieldID(17); + try writer.writeArray([]const u8, extension_order); + } + if (this.public_dir) |public_dir| { + try writer.writeFieldID(18); + try writer.writeValue(public_dir); + } + if (this.only_scan_dependencies) |only_scan_dependencies| { + try writer.writeFieldID(19); + try writer.writeEnum(only_scan_dependencies); + } + if (this.generate_node_module_bundle) |generate_node_module_bundle| { + try writer.writeFieldID(20); + try writer.writeInt(@intCast(u8, @boolToInt(generate_node_module_bundle))); + } + if (this.node_modules_bundle_path) |node_modules_bundle_path| { + try writer.writeFieldID(21); + try writer.writeValue(node_modules_bundle_path); + } + if (this.node_modules_bundle_path_server) |node_modules_bundle_path_server| { + try writer.writeFieldID(22); + try writer.writeValue(node_modules_bundle_path_server); + } + if (this.framework) |framework| { + try writer.writeFieldID(23); + try writer.writeValue(framework); + } + if (this.router) |router| { + try writer.writeFieldID(24); + try writer.writeValue(router); + } + try writer.endMessage(); + } + }; -/// line -line: i32 = 0, + pub const FileHandle = struct { + /// path + path: []const u8, -/// column -column: i32 = 0, + /// size + size: u32 = 0, -/// line_text -line_text: []const u8, + /// fd + fd: u32 = 0, -/// suggestion -suggestion: []const u8, + pub fn decode(reader: anytype) anyerror!FileHandle { + var this = std.mem.zeroes(FileHandle); -/// offset -offset: u32 = 0, + this.path = try reader.readValue([]const u8); + this.size = try reader.readValue(u32); + this.fd = try reader.readValue(u32); + return this; + } + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeInt(this.size); + try writer.writeInt(this.fd); + } + }; -pub fn decode(reader: anytype) anyerror!Location { - var this = std.mem.zeroes(Location); + pub const Transform = struct { + /// handle + handle: ?FileHandle = null, - this.file = try reader.readValue([]const u8); - this.namespace = try reader.readValue([]const u8); - this.line = try reader.readValue(i32); - this.column = try reader.readValue(i32); - this.line_text = try reader.readValue([]const u8); - this.suggestion = try reader.readValue([]const u8); - this.offset = try reader.readValue(u32); - return this; -} + /// path + path: ?[]const u8 = null, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.file); - try writer.writeValue(this.namespace); - try writer.writeInt(this.line); - try writer.writeInt(this.column); - try writer.writeValue(this.line_text); - try writer.writeValue(this.suggestion); - try writer.writeInt(this.offset); -} + /// contents + contents: []const u8, -}; + /// loader + loader: ?Loader = null, -pub const MessageData = struct { -/// text -text: ?[]const u8 = null, - -/// location -location: ?Location = null, - - -pub fn decode(reader: anytype) anyerror!MessageData { - var this = std.mem.zeroes(MessageData); - - while(true) { - switch (try reader.readByte()) { - 0 => { return this; }, - - 1 => { - this.text = try reader.readValue([]const u8); -}, - 2 => { - this.location = try reader.readValue(Location); -}, - else => { - return error.InvalidMessage; - }, - } - } -unreachable; -} + /// options + options: ?TransformOptions = null, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { -if (this.text) |text| { - try writer.writeFieldID(1); - try writer.writeValue(text); -} -if (this.location) |location| { - try writer.writeFieldID(2); - try writer.writeValue(location); -} -try writer.endMessage(); -} + pub fn decode(reader: anytype) anyerror!Transform { + var this = std.mem.zeroes(Transform); -}; + while (true) { + switch (try reader.readByte()) { + 0 => { + return this; + }, -pub const Message = struct { -/// kind -kind: MessageKind, + 1 => { + this.handle = try reader.readValue(FileHandle); + }, + 2 => { + this.path = try reader.readValue([]const u8); + }, + 3 => { + this.contents = try reader.readArray(u8); + }, + 4 => { + this.loader = try reader.readValue(Loader); + }, + 5 => { + this.options = try reader.readValue(TransformOptions); + }, + else => { + return error.InvalidMessage; + }, + } + } + unreachable; + } -/// data -data: MessageData, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.handle) |handle| { + try writer.writeFieldID(1); + try writer.writeValue(handle); + } + if (this.path) |path| { + try writer.writeFieldID(2); + try writer.writeValue(path); + } + if (this.contents) |contents| { + try writer.writeFieldID(3); + try writer.writeArray(u8, contents); + } + if (this.loader) |loader| { + try writer.writeFieldID(4); + try writer.writeEnum(loader); + } + if (this.options) |options| { + try writer.writeFieldID(5); + try writer.writeValue(options); + } + try writer.endMessage(); + } + }; -/// notes -notes: []const MessageData, + pub const TransformResponseStatus = enum(u32) { + _none, + /// success + success, + /// fail + fail, -pub fn decode(reader: anytype) anyerror!Message { - var this = std.mem.zeroes(Message); + _, - this.kind = try reader.readValue(MessageKind); - this.data = try reader.readValue(MessageData); - this.notes = try reader.readArray(MessageData); - return this; -} + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.kind); - try writer.writeValue(this.data); - try writer.writeArray(MessageData, this.notes); -} + pub const OutputFile = struct { + /// data + data: []const u8, -}; + /// path + path: []const u8, -pub const Log = struct { -/// warnings -warnings: u32 = 0, + pub fn decode(reader: anytype) anyerror!OutputFile { + var this = std.mem.zeroes(OutputFile); -/// errors -errors: u32 = 0, + this.data = try reader.readArray(u8); + this.path = try reader.readValue([]const u8); + return this; + } -/// msgs -msgs: []const Message, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(u8, this.data); + try writer.writeValue(this.path); + } + }; + pub const TransformResponse = struct { + /// status + status: TransformResponseStatus, -pub fn decode(reader: anytype) anyerror!Log { - var this = std.mem.zeroes(Log); + /// files + files: []const OutputFile, - this.warnings = try reader.readValue(u32); - this.errors = try reader.readValue(u32); - this.msgs = try reader.readArray(Message); - return this; -} + /// errors + errors: []const Message, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.warnings); - try writer.writeInt(this.errors); - try writer.writeArray(Message, this.msgs); -} + pub fn decode(reader: anytype) anyerror!TransformResponse { + var this = std.mem.zeroes(TransformResponse); -}; + this.status = try reader.readValue(TransformResponseStatus); + this.files = try reader.readArray(OutputFile); + this.errors = try reader.readArray(Message); + return this; + } -pub const Reloader = enum(u8) { + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.status); + try writer.writeArray(OutputFile, this.files); + try writer.writeArray(Message, this.errors); + } + }; -_none, - /// disable - disable, + pub const MessageKind = enum(u32) { + _none, + /// err + err, - /// live - live, + /// warn + warn, - /// fast_refresh - fast_refresh, + /// note + note, -_, + /// debug + debug, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } + _, - -}; + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; -pub const WebsocketMessageKind = enum(u8) { + pub const Location = struct { + /// file + file: []const u8, -_none, - /// welcome - welcome, + /// namespace + namespace: []const u8, - /// file_change_notification - file_change_notification, + /// line + line: i32 = 0, - /// build_success - build_success, + /// column + column: i32 = 0, - /// build_fail - build_fail, + /// line_text + line_text: []const u8, - /// manifest_success - manifest_success, + /// suggestion + suggestion: []const u8, - /// manifest_fail - manifest_fail, + /// offset + offset: u32 = 0, -_, + pub fn decode(reader: anytype) anyerror!Location { + var this = std.mem.zeroes(Location); - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } + this.file = try reader.readValue([]const u8); + this.namespace = try reader.readValue([]const u8); + this.line = try reader.readValue(i32); + this.column = try reader.readValue(i32); + this.line_text = try reader.readValue([]const u8); + this.suggestion = try reader.readValue([]const u8); + this.offset = try reader.readValue(u32); + return this; + } - -}; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.file); + try writer.writeValue(this.namespace); + try writer.writeInt(this.line); + try writer.writeInt(this.column); + try writer.writeValue(this.line_text); + try writer.writeValue(this.suggestion); + try writer.writeInt(this.offset); + } + }; -pub const WebsocketCommandKind = enum(u8) { + pub const MessageData = struct { + /// text + text: ?[]const u8 = null, -_none, - /// build - build, + /// location + location: ?Location = null, - /// manifest - manifest, + pub fn decode(reader: anytype) anyerror!MessageData { + var this = std.mem.zeroes(MessageData); -_, + while (true) { + switch (try reader.readByte()) { + 0 => { + return this; + }, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); + 1 => { + this.text = try reader.readValue([]const u8); + }, + 2 => { + this.location = try reader.readValue(Location); + }, + else => { + return error.InvalidMessage; + }, } + } + unreachable; + } - -}; - -pub const WebsocketMessage = struct { -/// timestamp -timestamp: u32 = 0, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.text) |text| { + try writer.writeFieldID(1); + try writer.writeValue(text); + } + if (this.location) |location| { + try writer.writeFieldID(2); + try writer.writeValue(location); + } + try writer.endMessage(); + } + }; -/// kind -kind: WebsocketMessageKind, + pub const Message = struct { + /// kind + kind: MessageKind, + /// data + data: MessageData, -pub fn decode(reader: anytype) anyerror!WebsocketMessage { - var this = std.mem.zeroes(WebsocketMessage); + /// notes + notes: []const MessageData, - this.timestamp = try reader.readValue(u32); - this.kind = try reader.readValue(WebsocketMessageKind); - return this; -} + pub fn decode(reader: anytype) anyerror!Message { + var this = std.mem.zeroes(Message); -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.timestamp); - try writer.writeEnum(this.kind); -} + this.kind = try reader.readValue(MessageKind); + this.data = try reader.readValue(MessageData); + this.notes = try reader.readArray(MessageData); + return this; + } -}; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.kind); + try writer.writeValue(this.data); + try writer.writeArray(MessageData, this.notes); + } + }; -pub const WebsocketMessageWelcome = struct { -/// epoch -epoch: u32 = 0, + pub const Log = struct { + /// warnings + warnings: u32 = 0, -/// javascriptReloader -javascript_reloader: Reloader, + /// errors + errors: u32 = 0, + /// msgs + msgs: []const Message, -pub fn decode(reader: anytype) anyerror!WebsocketMessageWelcome { - var this = std.mem.zeroes(WebsocketMessageWelcome); + pub fn decode(reader: anytype) anyerror!Log { + var this = std.mem.zeroes(Log); - this.epoch = try reader.readValue(u32); - this.javascript_reloader = try reader.readValue(Reloader); - return this; -} + this.warnings = try reader.readValue(u32); + this.errors = try reader.readValue(u32); + this.msgs = try reader.readArray(Message); + return this; + } -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.epoch); - try writer.writeEnum(this.javascript_reloader); -} + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.warnings); + try writer.writeInt(this.errors); + try writer.writeArray(Message, this.msgs); + } + }; -}; + pub const Reloader = enum(u8) { + _none, + /// disable + disable, -pub const WebsocketMessageFileChangeNotification = struct { -/// id -id: u32 = 0, + /// live + live, -/// loader -loader: Loader, + /// fast_refresh + fast_refresh, + _, -pub fn decode(reader: anytype) anyerror!WebsocketMessageFileChangeNotification { - var this = std.mem.zeroes(WebsocketMessageFileChangeNotification); + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; - this.id = try reader.readValue(u32); - this.loader = try reader.readValue(Loader); - return this; -} + pub const WebsocketMessageKind = enum(u8) { + _none, + /// welcome + welcome, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - try writer.writeEnum(this.loader); -} + /// file_change_notification + file_change_notification, -}; + /// build_success + build_success, -pub const WebsocketCommand = struct { -/// kind -kind: WebsocketCommandKind, + /// build_fail + build_fail, -/// timestamp -timestamp: u32 = 0, + /// manifest_success + manifest_success, + /// manifest_fail + manifest_fail, -pub fn decode(reader: anytype) anyerror!WebsocketCommand { - var this = std.mem.zeroes(WebsocketCommand); + _, - this.kind = try reader.readValue(WebsocketCommandKind); - this.timestamp = try reader.readValue(u32); - return this; -} + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.kind); - try writer.writeInt(this.timestamp); -} + pub const WebsocketCommandKind = enum(u8) { + _none, + /// build + build, -}; + /// manifest + manifest, -pub const WebsocketCommandBuild = packed struct { -/// id -id: u32 = 0, + _, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } + }; -pub fn decode(reader: anytype) anyerror!WebsocketCommandBuild { - var this = std.mem.zeroes(WebsocketCommandBuild); + pub const WebsocketMessage = struct { + /// timestamp + timestamp: u32 = 0, - this.id = try reader.readValue(u32); - return this; -} + /// kind + kind: WebsocketMessageKind, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); -} + pub fn decode(reader: anytype) anyerror!WebsocketMessage { + var this = std.mem.zeroes(WebsocketMessage); -}; + this.timestamp = try reader.readValue(u32); + this.kind = try reader.readValue(WebsocketMessageKind); + return this; + } -pub const WebsocketCommandManifest = packed struct { -/// id -id: u32 = 0, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.timestamp); + try writer.writeEnum(this.kind); + } + }; + pub const WebsocketMessageWelcome = struct { + /// epoch + epoch: u32 = 0, -pub fn decode(reader: anytype) anyerror!WebsocketCommandManifest { - var this = std.mem.zeroes(WebsocketCommandManifest); + /// javascriptReloader + javascript_reloader: Reloader, - this.id = try reader.readValue(u32); - return this; -} + pub fn decode(reader: anytype) anyerror!WebsocketMessageWelcome { + var this = std.mem.zeroes(WebsocketMessageWelcome); -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); -} + this.epoch = try reader.readValue(u32); + this.javascript_reloader = try reader.readValue(Reloader); + return this; + } -}; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.epoch); + try writer.writeEnum(this.javascript_reloader); + } + }; -pub const WebsocketMessageBuildSuccess = struct { -/// id -id: u32 = 0, + pub const WebsocketMessageFileChangeNotification = struct { + /// id + id: u32 = 0, -/// from_timestamp -from_timestamp: u32 = 0, + /// loader + loader: Loader, -/// loader -loader: Loader, + pub fn decode(reader: anytype) anyerror!WebsocketMessageFileChangeNotification { + var this = std.mem.zeroes(WebsocketMessageFileChangeNotification); -/// module_path -module_path: []const u8, + this.id = try reader.readValue(u32); + this.loader = try reader.readValue(Loader); + return this; + } -/// blob_length -blob_length: u32 = 0, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + try writer.writeEnum(this.loader); + } + }; + pub const WebsocketCommand = struct { + /// kind + kind: WebsocketCommandKind, -pub fn decode(reader: anytype) anyerror!WebsocketMessageBuildSuccess { - var this = std.mem.zeroes(WebsocketMessageBuildSuccess); + /// timestamp + timestamp: u32 = 0, - this.id = try reader.readValue(u32); - this.from_timestamp = try reader.readValue(u32); - this.loader = try reader.readValue(Loader); - this.module_path = try reader.readValue([]const u8); - this.blob_length = try reader.readValue(u32); - return this; -} + pub fn decode(reader: anytype) anyerror!WebsocketCommand { + var this = std.mem.zeroes(WebsocketCommand); -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - try writer.writeInt(this.from_timestamp); - try writer.writeEnum(this.loader); - try writer.writeValue(this.module_path); - try writer.writeInt(this.blob_length); -} + this.kind = try reader.readValue(WebsocketCommandKind); + this.timestamp = try reader.readValue(u32); + return this; + } -}; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.kind); + try writer.writeInt(this.timestamp); + } + }; -pub const WebsocketMessageBuildFailure = struct { -/// id -id: u32 = 0, + pub const WebsocketCommandBuild = packed struct { + /// id + id: u32 = 0, -/// from_timestamp -from_timestamp: u32 = 0, + pub fn decode(reader: anytype) anyerror!WebsocketCommandBuild { + var this = std.mem.zeroes(WebsocketCommandBuild); -/// loader -loader: Loader, + this.id = try reader.readValue(u32); + return this; + } -/// module_path -module_path: []const u8, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + } + }; -/// log -log: Log, + pub const WebsocketCommandManifest = packed struct { + /// id + id: u32 = 0, + pub fn decode(reader: anytype) anyerror!WebsocketCommandManifest { + var this = std.mem.zeroes(WebsocketCommandManifest); -pub fn decode(reader: anytype) anyerror!WebsocketMessageBuildFailure { - var this = std.mem.zeroes(WebsocketMessageBuildFailure); + this.id = try reader.readValue(u32); + return this; + } - this.id = try reader.readValue(u32); - this.from_timestamp = try reader.readValue(u32); - this.loader = try reader.readValue(Loader); - this.module_path = try reader.readValue([]const u8); - this.log = try reader.readValue(Log); - return this; -} + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + } + }; -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - try writer.writeInt(this.from_timestamp); - try writer.writeEnum(this.loader); - try writer.writeValue(this.module_path); - try writer.writeValue(this.log); -} + pub const WebsocketMessageBuildSuccess = struct { + /// id + id: u32 = 0, -}; + /// from_timestamp + from_timestamp: u32 = 0, -pub const DependencyManifest = struct { -/// ids -ids: []const u32, + /// loader + loader: Loader, + /// module_path + module_path: []const u8, -pub fn decode(reader: anytype) anyerror!DependencyManifest { - var this = std.mem.zeroes(DependencyManifest); + /// blob_length + blob_length: u32 = 0, - this.ids = try reader.readArray(u32); - return this; -} + pub fn decode(reader: anytype) anyerror!WebsocketMessageBuildSuccess { + var this = std.mem.zeroes(WebsocketMessageBuildSuccess); -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(u32, this.ids); -} + this.id = try reader.readValue(u32); + this.from_timestamp = try reader.readValue(u32); + this.loader = try reader.readValue(Loader); + this.module_path = try reader.readValue([]const u8); + this.blob_length = try reader.readValue(u32); + return this; + } -}; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + try writer.writeInt(this.from_timestamp); + try writer.writeEnum(this.loader); + try writer.writeValue(this.module_path); + try writer.writeInt(this.blob_length); + } + }; -pub const FileList = struct { -/// ptrs -ptrs: []const StringPointer, + pub const WebsocketMessageBuildFailure = struct { + /// id + id: u32 = 0, -/// files -files: []const u8, + /// from_timestamp + from_timestamp: u32 = 0, + /// loader + loader: Loader, -pub fn decode(reader: anytype) anyerror!FileList { - var this = std.mem.zeroes(FileList); + /// module_path + module_path: []const u8, - this.ptrs = try reader.readArray(StringPointer); - this.files = try reader.readValue([]const u8); - return this; -} + /// log + log: Log, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(StringPointer, this.ptrs); - try writer.writeValue(this.files); -} + pub fn decode(reader: anytype) anyerror!WebsocketMessageBuildFailure { + var this = std.mem.zeroes(WebsocketMessageBuildFailure); -}; + this.id = try reader.readValue(u32); + this.from_timestamp = try reader.readValue(u32); + this.loader = try reader.readValue(Loader); + this.module_path = try reader.readValue([]const u8); + this.log = try reader.readValue(Log); + return this; + } -pub const WebsocketMessageResolveIDs = struct { -/// id -id: []const u32, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + try writer.writeInt(this.from_timestamp); + try writer.writeEnum(this.loader); + try writer.writeValue(this.module_path); + try writer.writeValue(this.log); + } + }; -/// list -list: FileList, + pub const DependencyManifest = struct { + /// ids + ids: []const u32, + pub fn decode(reader: anytype) anyerror!DependencyManifest { + var this = std.mem.zeroes(DependencyManifest); -pub fn decode(reader: anytype) anyerror!WebsocketMessageResolveIDs { - var this = std.mem.zeroes(WebsocketMessageResolveIDs); + this.ids = try reader.readArray(u32); + return this; + } - this.id = try reader.readArray(u32); - this.list = try reader.readValue(FileList); - return this; -} + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(u32, this.ids); + } + }; -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(u32, this.id); - try writer.writeValue(this.list); -} + pub const FileList = struct { + /// ptrs + ptrs: []const StringPointer, -}; + /// files + files: []const u8, -pub const WebsocketCommandResolveIDs = struct { -/// ptrs -ptrs: []const StringPointer, + pub fn decode(reader: anytype) anyerror!FileList { + var this = std.mem.zeroes(FileList); -/// files -files: []const u8, + this.ptrs = try reader.readArray(StringPointer); + this.files = try reader.readValue([]const u8); + return this; + } + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(StringPointer, this.ptrs); + try writer.writeValue(this.files); + } + }; -pub fn decode(reader: anytype) anyerror!WebsocketCommandResolveIDs { - var this = std.mem.zeroes(WebsocketCommandResolveIDs); + pub const WebsocketMessageResolveIDs = struct { + /// id + id: []const u32, - this.ptrs = try reader.readArray(StringPointer); - this.files = try reader.readValue([]const u8); - return this; -} + /// list + list: FileList, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(StringPointer, this.ptrs); - try writer.writeValue(this.files); -} + pub fn decode(reader: anytype) anyerror!WebsocketMessageResolveIDs { + var this = std.mem.zeroes(WebsocketMessageResolveIDs); -}; + this.id = try reader.readArray(u32); + this.list = try reader.readValue(FileList); + return this; + } -pub const WebsocketMessageManifestSuccess = struct { -/// id -id: u32 = 0, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(u32, this.id); + try writer.writeValue(this.list); + } + }; -/// module_path -module_path: []const u8, + pub const WebsocketCommandResolveIDs = struct { + /// ptrs + ptrs: []const StringPointer, -/// loader -loader: Loader, + /// files + files: []const u8, -/// manifest -manifest: DependencyManifest, + pub fn decode(reader: anytype) anyerror!WebsocketCommandResolveIDs { + var this = std.mem.zeroes(WebsocketCommandResolveIDs); + this.ptrs = try reader.readArray(StringPointer); + this.files = try reader.readValue([]const u8); + return this; + } -pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestSuccess { - var this = std.mem.zeroes(WebsocketMessageManifestSuccess); + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(StringPointer, this.ptrs); + try writer.writeValue(this.files); + } + }; - this.id = try reader.readValue(u32); - this.module_path = try reader.readValue([]const u8); - this.loader = try reader.readValue(Loader); - this.manifest = try reader.readValue(DependencyManifest); - return this; -} + pub const WebsocketMessageManifestSuccess = struct { + /// id + id: u32 = 0, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - try writer.writeValue(this.module_path); - try writer.writeEnum(this.loader); - try writer.writeValue(this.manifest); -} + /// module_path + module_path: []const u8, -}; + /// loader + loader: Loader, -pub const WebsocketMessageManifestFailure = struct { -/// id -id: u32 = 0, + /// manifest + manifest: DependencyManifest, -/// from_timestamp -from_timestamp: u32 = 0, + pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestSuccess { + var this = std.mem.zeroes(WebsocketMessageManifestSuccess); -/// loader -loader: Loader, + this.id = try reader.readValue(u32); + this.module_path = try reader.readValue([]const u8); + this.loader = try reader.readValue(Loader); + this.manifest = try reader.readValue(DependencyManifest); + return this; + } -/// log -log: Log, + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + try writer.writeValue(this.module_path); + try writer.writeEnum(this.loader); + try writer.writeValue(this.manifest); + } + }; + pub const WebsocketMessageManifestFailure = struct { + /// id + id: u32 = 0, -pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestFailure { - var this = std.mem.zeroes(WebsocketMessageManifestFailure); + /// from_timestamp + from_timestamp: u32 = 0, - this.id = try reader.readValue(u32); - this.from_timestamp = try reader.readValue(u32); - this.loader = try reader.readValue(Loader); - this.log = try reader.readValue(Log); - return this; -} + /// loader + loader: Loader, -pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - try writer.writeInt(this.from_timestamp); - try writer.writeEnum(this.loader); - try writer.writeValue(this.log); -} + /// log + log: Log, -}; + pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestFailure { + var this = std.mem.zeroes(WebsocketMessageManifestFailure); + this.id = try reader.readValue(u32); + this.from_timestamp = try reader.readValue(u32); + this.loader = try reader.readValue(Loader); + this.log = try reader.readValue(Log); + return this; + } + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + try writer.writeInt(this.from_timestamp); + try writer.writeEnum(this.loader); + try writer.writeValue(this.log); + } + }; }; - const ExamplePackedStruct = packed struct { len: u32 = 0, offset: u32 = 0, diff --git a/src/bundler.zig b/src/bundler.zig index 067597b84..4769cc8ee 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -214,37 +214,39 @@ pub fn NewBundler(cache_files: bool) type { pub fn configureFramework(this: *ThisBundler) !void { if (this.options.framework) |*framework| { - var framework_file = this.normalizeEntryPointPath(framework.entry_point); - var resolved = this.resolver.resolve( - this.fs.top_level_dir, - framework_file, - .entry_point, - ) catch |err| { - Output.prettyErrorln("Failed to load framework: {s}", .{@errorName(err)}); - Output.flush(); - this.options.framework = null; - return; - }; + if (framework.needsResolveFromPackage()) { + var route_config = this.options.route_config orelse options.RouteConfig.zero(); + var pair = PackageJSON.FrameworkRouterPair{ .framework = framework, .router = &route_config }; + + if (framework.development) { + try this.resolver.resolveFramework(framework.package, &pair, .development); + } else { + try this.resolver.resolveFramework(framework.package, &pair, .production); + } - framework.entry_point = try this.allocator.dupe(u8, resolved.path_pair.primary.text); + if (pair.loaded_routes) { + this.options.route_config = route_config; + } + framework.resolved = true; + this.options.framework = framework.*; + } else if (!framework.resolved) { + Global.panic("directly passing framework path is not implemented yet!", .{}); + } } } - pub fn configureFrameworkWithResolveResult(this: *ThisBundler) ?_resolver.Result { - if (this.options.framework) |*framework| { - var framework_file = this.normalizeEntryPointPath(framework.entry_point); - const result = this.resolver.resolve( - this.fs.top_level_dir, - framework_file, - .entry_point, - ) catch |err| { - Output.prettyErrorln("Failed to load framework: {s}", .{@errorName(err)}); - Output.flush(); - this.options.framework = null; - return null; - }; - framework.entry_point = result.path_pair.primary.text; - return result; + pub fn configureFrameworkWithResolveResult(this: *ThisBundler, comptime client: bool) !?_resolver.Result { + if (this.options.framework != null) { + try this.configureFramework(); + if (comptime client) { + if (this.options.framework.?.client.len > 0) { + return try this.resolver.resolve(this.fs.top_level_dir, this.options.framework.?.client, .internal); + } + } else { + if (this.options.framework.?.server.len > 0) { + return try this.resolver.resolve(this.fs.top_level_dir, this.options.framework.?.server, .internal); + } + } } return null; @@ -284,9 +286,7 @@ pub fn NewBundler(cache_files: bool) type { } } } else if (this.options.route_config) |*route_config| { - var paths = [_]string{route_config.dir}; - var entry = this.fs.abs(&paths); - var dir_info_ = try this.resolver.readDirInfo(entry); + var dir_info_ = try this.resolver.readDirInfo(route_config.dir); var dir_info = dir_info_ orelse return error.MissingRoutesDir; this.options.route_config = options.RouteConfig{ @@ -367,11 +367,24 @@ pub fn NewBundler(cache_files: bool) type { }; } - pub fn generate(bundler: *ThisBundler, allocator: *std.mem.Allocator, destination: string) !Api.JavascriptBundleContainer { - var tmpdir: std.fs.Dir = bundler.fs.tmpdir(); - const tmpname = try bundler.fs.tmpname(".jsb"); + pub fn generate( + bundler: *ThisBundler, + allocator: *std.mem.Allocator, + framework_config: ?Api.LoadedFramework, + route_config: ?Api.LoadedRouteConfig, + destination: [*:0]const u8, + ) !Api.JavascriptBundleContainer { + var tmpdir: std.fs.Dir = try bundler.fs.fs.openTmpDir(); + var tmpname_buf: [64]u8 = undefined; + + const tmpname = try bundler.fs.tmpname( + ".jsb", + std.mem.span(&tmpname_buf), + std.hash.Wyhash.hash(0, std.mem.span(destination)), + ); + + var tmpfile = try tmpdir.createFileZ(tmpname, .{ .read = isDebug, .exclusive = true }); - var tmpfile = try tmpdir.createFile(tmpname, .{ .read = isDebug }); var generator = GenerateNodeModuleBundle{ .module_list = std.ArrayList(Api.JavascriptBundledModule).init(allocator), .package_list = std.ArrayList(Api.JavascriptBundledPackage).init(allocator), @@ -401,15 +414,39 @@ pub fn NewBundler(cache_files: bool) type { bundler.resolver.debug_logs = try DebugLogs.init(allocator); } - if (bundler.configureFrameworkWithResolveResult()) |result| { - try this.resolve_queue.writeItem(result); + if (bundler.router) |router| { + const entry_points = try router.getEntryPoints(allocator); + try this.resolve_queue.ensureUnusedCapacity(entry_points.len + bundler.options.entry_points.len + @intCast(usize, @boolToInt(framework_config != null))); + for (entry_points) |entry_point| { + const source_dir = bundler.fs.top_level_dir; + const resolved = try bundler.linker.resolver.resolve(source_dir, entry_point, .entry_point); + this.resolve_queue.writeItemAssumeCapacity(resolved); + } + } else { + try this.resolve_queue.ensureUnusedCapacity(bundler.options.entry_points.len + @intCast(usize, @boolToInt(framework_config != null))); } for (bundler.options.entry_points) |entry_point| { const entry_point_path = bundler.normalizeEntryPointPath(entry_point); const source_dir = bundler.fs.top_level_dir; const resolved = try bundler.linker.resolver.resolve(source_dir, entry_point, .entry_point); - try this.resolve_queue.writeItem(resolved); + this.resolve_queue.writeItemAssumeCapacity(resolved); + } + + if (framework_config) |conf| { + if (conf.client) { + if (bundler.configureFrameworkWithResolveResult(true)) |result_| { + if (result_) |result| { + this.resolve_queue.writeItemAssumeCapacity(result); + } + } else |err| {} + } else { + if (bundler.configureFrameworkWithResolveResult(false)) |result_| { + if (result_) |result| { + this.resolve_queue.writeItemAssumeCapacity(result); + } + } else |err| {} + } } while (this.resolve_queue.readItem()) |resolved| { @@ -504,7 +541,7 @@ pub fn NewBundler(cache_files: bool) type { javascript_bundle.etag = try std.fmt.allocPrint(allocator, "{x}", .{etag_u64}); javascript_bundle.generated_at = @truncate(u32, @intCast(u64, std.time.milliTimestamp())); - const basename = std.fs.path.basename(destination); + const basename = std.fs.path.basename(std.mem.span(destination)); const extname = std.fs.path.extension(basename); javascript_bundle.import_from_name = try std.fmt.allocPrint( this.allocator, @@ -518,6 +555,8 @@ pub fn NewBundler(cache_files: bool) type { javascript_bundle_container.bundle_format_version = current_version; javascript_bundle_container.bundle = javascript_bundle; javascript_bundle_container.code_length = this.code_end_byte_offset; + javascript_bundle_container.framework = framework_config; + javascript_bundle_container.routes = route_config; var start_pos = try this.tmpfile.getPos(); var tmpwriter = std.io.bufferedWriter(this.tmpfile.writer()); @@ -544,16 +583,27 @@ pub fn NewBundler(cache_files: bool) type { std.mem.writeIntNative(u32, &code_length_bytes, this.code_end_byte_offset); _ = try std.os.pwrite(this.tmpfile.handle, &code_length_bytes, magic_bytes.len); - const top_dir = try std.fs.openDirAbsolute(this.bundler.fs.top_level_dir, .{}); + // Without his mutex, we get a crash at this location: + // try std.os.renameat(tmpdir.fd, tmpname, top_dir.fd, destination); + // ^ + const top_dir = try std.fs.openDirAbsolute(Fs.FileSystem.instance.top_level_dir, .{}); _ = C.fchmod( this.tmpfile.handle, // chmod 777 0000010 | 0000100 | 0000001 | 0001000 | 0000040 | 0000004 | 0000002 | 0000400 | 0000200 | 0000020, ); - try std.os.renameat(tmpdir.fd, tmpname, top_dir.fd, destination); + // Delete if already exists, ignoring errors + // std.os.unlinkatZ(top_dir.fd, destination, 0) catch {}; + tmpdir = bundler.fs.tmpdir(); + defer { + tmpdir.close(); + bundler.fs._tmpdir = null; + } + + try std.os.renameatZ(tmpdir.fd, tmpname, top_dir.fd, destination); // Print any errors at the end - try this.log.print(Output.errorWriter()); + // try this.log.print(Output.errorWriter()); return javascript_bundle_container; } @@ -594,7 +644,7 @@ pub fn NewBundler(cache_files: bool) type { fn processImportRecord(this: *GenerateNodeModuleBundle, import_record: ImportRecord) !void {} const node_module_root_string = "node_modules" ++ std.fs.path.sep_str; threadlocal var package_key_buf: [512]u8 = undefined; - + threadlocal var file_path_buf: [4096]u8 = undefined; fn processFile(this: *GenerateNodeModuleBundle, _resolve: _resolver.Result) !void { var resolve = _resolve; if (resolve.is_external) return; @@ -605,6 +655,13 @@ pub fn NewBundler(cache_files: bool) type { defer this.scan_pass_result.reset(); defer this.bundler.resetStore(); var file_path = resolve.path_pair.primary; + std.mem.copy(u8, file_path_buf[0..file_path.text.len], resolve.path_pair.primary.text); + file_path.text = file_path_buf[0..file_path.text.len]; + if (file_path.pretty.len > 0) { + std.mem.copy(u8, file_path_buf[file_path.text.len..], resolve.path_pair.primary.pretty); + file_path.pretty = file_path_buf[file_path.text.len..][0..resolve.path_pair.primary.pretty.len]; + file_path.name = Fs.PathName.init(file_path.text); + } var hasher = std.hash.Wyhash.init(0); // If we're in a node_module, build that almost normally diff --git a/src/cli.zig b/src/cli.zig index cf1791d1e..7c6af7c26 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -14,14 +14,16 @@ const linker = @import("linker.zig"); usingnamespace @import("ast/base.zig"); usingnamespace @import("defines.zig"); const panicky = @import("panic_handler.zig"); +const sync = @import("./sync.zig"); const Api = @import("api/schema.zig").Api; const resolve_path = @import("./resolver/resolve_path.zig"); - +const configureTransformOptionsForSpeedy = @import("./javascript/jsc/config.zig").configureTransformOptionsForSpeedy; const clap = @import("clap"); const bundler = @import("bundler.zig"); const fs = @import("fs.zig"); +const Router = @import("./router.zig"); const NodeModuleBundle = @import("./node_module_bundle.zig").NodeModuleBundle; @@ -114,7 +116,7 @@ pub const Cli = struct { clap.parseParam("-e, --external <STR>... Exclude module from transpilation (can use * wildcards). ex: -e react") catch unreachable, clap.parseParam("-i, --inject <STR>... Inject module at the top of every file") catch unreachable, clap.parseParam("--cwd <STR> Absolute path to resolve entry points from. Defaults to cwd") catch unreachable, - clap.parseParam("--public-url <STR> Rewrite import paths to start with --public-url. Useful for web browsers.") catch unreachable, + clap.parseParam("--origin <STR> Rewrite import paths to start with --origin. Useful for web browsers.") catch unreachable, clap.parseParam("--serve Start a local dev server. This also sets resolve to \"lazy\".") catch unreachable, clap.parseParam("--public-dir <STR> Top-level directory for .html files, fonts, images, or anything external. Only relevant with --serve. Defaults to \"<cwd>/public\", to match create-react-app and Next.js") catch unreachable, clap.parseParam("--jsx-factory <STR> Changes the function called when compiling JSX elements using the classic JSX runtime") catch unreachable, @@ -130,7 +132,10 @@ pub const Cli = struct { clap.parseParam("--scan Instead of bundling or transpiling, print a list of every file imported by an entry point, recursively") catch unreachable, clap.parseParam("--new-jsb Generate a new node_modules.jsb file from node_modules and entry point(s)") catch unreachable, clap.parseParam("--jsb <STR> Use a Speedy JavaScript Bundle (default: \"./node_modules.jsb\" if exists)") catch unreachable, - clap.parseParam("--framework <STR> Use a JavaScript framework (module path)") catch unreachable, + clap.parseParam("--jsb-for-server <STR> Use a server-only Speedy JavaScript Bundle (default: \"./node_modules.server.jsb\" if exists)") catch unreachable, + clap.parseParam("--framework <STR> Use a JavaScript framework (package name or path to package)") catch unreachable, + clap.parseParam("--production This sets the defaults to production. Applies to jsx & framework") catch unreachable, + clap.parseParam("<POS>... Entry point(s) to use. Can be individual files, npm packages, or one directory. If one directory, it will auto-detect entry points using a filesystem router. If you're using a framework, passing entry points are optional.") catch unreachable, }; @@ -150,7 +155,7 @@ pub const Cli = struct { var cwd_paths = [_]string{args.option("--cwd") orelse try std.process.getCwdAlloc(allocator)}; var cwd = try std.fs.path.resolve(allocator, &cwd_paths); var tsconfig_override = if (args.option("--tsconfig-override")) |ts| (Arguments.readFile(allocator, cwd, ts) catch |err| fileReadError(err, stderr, ts, "tsconfig.json")) else null; - var public_url = args.option("--public-url"); + var origin = args.option("--origin"); var defines_tuple = try DefineColonList.resolve(allocator, args.options("--define")); var loader_tuple = try LoaderColonList.resolve(allocator, args.options("--define")); @@ -163,6 +168,8 @@ pub const Cli = struct { var output_dir = args.option("--outdir"); const serve = args.flag("--serve"); + const production = args.flag("--production"); + var write = entry_points.len > 1 or output_dir != null; if (write and output_dir == null) { var _paths = [_]string{ cwd, "out" }; @@ -180,7 +187,7 @@ pub const Cli = struct { var jsx_fragment = args.option("--jsx-fragment"); var jsx_import_source = args.option("--jsx-import-source"); var jsx_runtime = args.option("--jsx-runtime"); - var jsx_production = args.flag("--jsx-production"); + var jsx_production = args.flag("--jsx-production") or production; var react_fast_refresh = false; var framework_entry_point = args.option("--framework"); @@ -200,10 +207,18 @@ pub const Cli = struct { } const node_modules_bundle_path_absolute = resolve_path.joinAbs(cwd, .auto, "node_modules.jsb"); - std.fs.accessAbsolute(node_modules_bundle_path_absolute, .{}) catch |err| { + + break :brk std.fs.realpathAlloc(allocator, node_modules_bundle_path_absolute) catch null; + }; + + var node_modules_bundle_path_server = args.option("--jsb-for-server") orelse brk: { + if (args.flag("--new-jsb")) { break :brk null; - }; - break :brk try std.fs.realpathAlloc(allocator, node_modules_bundle_path_absolute); + } + + const node_modules_bundle_path_absolute = resolve_path.joinAbs(cwd, .auto, "node_modules.server.jsb"); + + break :brk std.fs.realpathAlloc(allocator, node_modules_bundle_path_absolute) catch null; }; if (args.flag("--new-jsb")) { @@ -280,11 +295,12 @@ pub const Cli = struct { if (framework_entry_point) |entry| { javascript_framework = Api.FrameworkConfig{ - .entry_point = entry, + .package = entry, + .development = !production, }; } - if (entry_points.len == 0 and javascript_framework == null) { + if (entry_points.len == 0 and javascript_framework == null and node_modules_bundle_path == null) { try clap.help(stderr.writer(), ¶ms); try diag.report(stderr.writer(), error.MissingEntryPoint); std.process.exit(1); @@ -297,7 +313,7 @@ pub const Cli = struct { .external = externals, .absolute_working_dir = cwd, .tsconfig_override = tsconfig_override, - .public_url = public_url, + .origin = origin, .define = .{ .keys = define_keys, .values = define_values, @@ -307,6 +323,7 @@ pub const Cli = struct { .loaders = loader_values, }, .node_modules_bundle_path = node_modules_bundle_path, + .node_modules_bundle_path_server = node_modules_bundle_path_server, .public_dir = if (args.option("--public-dir")) |public_dir| allocator.dupe(u8, public_dir) catch unreachable else null, .write = write, .serve = serve, @@ -336,6 +353,7 @@ pub const Cli = struct { try std.json.stringify(scan_results.list(), .{}, stdout.writer()); Output.printError("\nJSON printing took: {d}\n", .{std.time.nanoTimestamp() - print_start}); } + var wait_group: sync.WaitGroup = undefined; pub fn startTransform(allocator: *std.mem.Allocator, args: Api.TransformOptions, log: *logger.Log) anyerror!void {} pub fn start(allocator: *std.mem.Allocator, stdout: anytype, stderr: anytype, comptime MainPanicHandler: type) anyerror!void { const start_time = std.time.nanoTimestamp(); @@ -378,18 +396,128 @@ pub const Cli = struct { } if ((args.generate_node_module_bundle orelse false)) { - var this_bundler = try bundler.ServeBundler.init(allocator, &log, args, null); + var log_ = try allocator.create(logger.Log); + log_.* = log; + + var this_bundler = try bundler.ServeBundler.init(allocator, log_, args, null); this_bundler.configureLinker(); - var filepath = "node_modules.jsb"; - var node_modules = try bundler.ServeBundler.GenerateNodeModuleBundle.generate(&this_bundler, allocator, filepath); + var filepath: [*:0]const u8 = "node_modules.jsb"; + var server_bundle_filepath: [*:0]const u8 = "node_modules.server.jsb"; + try this_bundler.configureRouter(); + + var loaded_route_config: ?Api.LoadedRouteConfig = brk: { + if (this_bundler.options.route_config) |*conf| { + break :brk conf.toAPI(); + } + break :brk null; + }; + var loaded_framework: ?Api.LoadedFramework = brk: { + if (this_bundler.options.framework) |*conf| { + break :brk conf.toAPI(allocator, this_bundler.fs.top_level_dir, true); + } + break :brk null; + }; - var elapsed = @divTrunc(std.time.nanoTimestamp() - start_time, @as(i128, std.time.ns_per_ms)); - var bundle = NodeModuleBundle.init(node_modules, allocator); + wait_group = sync.WaitGroup.init(); + var server_bundler_generator_thread: ?std.Thread = null; + if (this_bundler.options.framework) |*framework| { + if (framework.toAPI(allocator, this_bundler.fs.top_level_dir, false)) |_server_conf| { + const ServerBundleGeneratorThread = struct { + inline fn _generate( + logs: *logger.Log, + allocator_: *std.mem.Allocator, + transform_args: Api.TransformOptions, + _filepath: [*:0]const u8, + server_conf: Api.LoadedFramework, + route_conf_: ?Api.LoadedRouteConfig, + router: ?Router, + ) !void { + var server_bundler = try bundler.ServeBundler.init(allocator_, logs, try configureTransformOptionsForSpeedy(allocator_, transform_args), null); + server_bundler.configureLinker(); + server_bundler.router = router; + _ = try bundler.ServeBundler.GenerateNodeModuleBundle.generate( + &server_bundler, + allocator_, + server_conf, + route_conf_, + _filepath, + ); + std.mem.doNotOptimizeAway(&server_bundler); + } + pub fn generate( + logs: *logger.Log, + transform_args: Api.TransformOptions, + _filepath: [*:0]const u8, + server_conf: Api.LoadedFramework, + route_conf_: ?Api.LoadedRouteConfig, + router: ?Router, + ) void { + try alloc.setup(std.heap.c_allocator); + var stdout_ = std.io.getStdOut(); + var stderr_ = std.io.getStdErr(); + var output_source = Output.Source.init(stdout_, stderr_); + Output.Source.set(&output_source); + + defer Output.flush(); + defer wait_group.done(); + Output.enable_ansi_colors = stderr_.isTty(); + _generate(logs, std.heap.c_allocator, transform_args, _filepath, server_conf, route_conf_, router) catch return; + } + }; + + wait_group.add(); + server_bundler_generator_thread = try std.Thread.spawn( + .{}, + ServerBundleGeneratorThread.generate, + .{ + log_, + args, + server_bundle_filepath, + _server_conf, + loaded_route_config, + this_bundler.router, + }, + ); + } + } - bundle.printSummary(); - const indent = comptime " "; - Output.prettyln(indent ++ "<d>{d:6}ms elapsed", .{@intCast(u32, elapsed)}); - Output.prettyln(indent ++ "<r>Saved to ./{s}", .{filepath}); + defer { + if (server_bundler_generator_thread) |thread| { + thread.join(); + } + } + + { + // Always generate the client-only bundle + // we can revisit this decision if people ask + var node_modules = try bundler.ServeBundler.GenerateNodeModuleBundle.generate( + &this_bundler, + allocator, + loaded_framework, + loaded_route_config, + filepath, + ); + if (server_bundler_generator_thread) |thread| { + wait_group.wait(); + } + + var elapsed = @divTrunc(std.time.nanoTimestamp() - start_time, @as(i128, std.time.ns_per_ms)); + var bundle = NodeModuleBundle.init(node_modules, allocator); + + if (log.errors > 0 or log.warnings > 0) { + try log.print(Output.errorWriter()); + } else { + bundle.printSummary(); + const indent = comptime " "; + Output.prettyln(indent ++ "<d>{d:6}ms elapsed", .{@intCast(u32, elapsed)}); + + if (server_bundler_generator_thread != null) { + Output.prettyln(indent ++ "<r>Saved to ./{s}, ./{s}", .{ filepath, server_bundle_filepath }); + } else { + Output.prettyln(indent ++ "<r>Saved to ./{s}", .{filepath}); + } + } + } return; } diff --git a/src/fs.zig b/src/fs.zig index f45c53c29..d37706b45 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -77,18 +77,19 @@ pub const FileSystem = struct { _tmpdir: ?std.fs.Dir = null, + threadlocal var tmpdir_handle: ?std.fs.Dir = null; + pub fn tmpdir(fs: *FileSystem) std.fs.Dir { - if (fs._tmpdir == null) { - fs._tmpdir = fs.fs.openTmpDir() catch unreachable; + if (tmpdir_handle == null) { + tmpdir_handle = fs.fs.openTmpDir() catch unreachable; } - return fs._tmpdir.?; + return tmpdir_handle.?; } - var tmpname_buf: [64]u8 = undefined; - pub fn tmpname(fs: *const FileSystem, extname: string) !string { - const int = std.crypto.random.int(u64); - return try std.fmt.bufPrint(&tmpname_buf, "{x}{s}", .{ int, extname }); + pub fn tmpname(fs: *const FileSystem, extname: string, buf: []u8, hash: u64) ![*:0]u8 { + // PRNG was...not so random + return try std.fmt.bufPrintZ(buf, "{x}{s}", .{ @truncate(u64, @intCast(u128, hash) * @intCast(u128, std.time.nanoTimestamp())), extname }); } pub var max_fd: FileDescriptorType = 0; @@ -100,7 +101,7 @@ pub const FileSystem = struct { max_fd = std.math.max(fd, max_fd); } - + pub var instance_loaded: bool = false; pub var instance: FileSystem = undefined; pub const DirnameStore = allocators.BSSStringList(Preallocate.Counts.dir_entry, 128); @@ -131,20 +132,24 @@ pub const FileSystem = struct { _top_level_dir = tld; } - instance = FileSystem{ - .allocator = allocator, - .top_level_dir = _top_level_dir, - .fs = Implementation.init( - allocator, - _top_level_dir, - ), - // .stats = std.StringHashMap(Stat).init(allocator), - .dirname_store = DirnameStore.init(allocator), - .filename_store = FilenameStore.init(allocator), - }; + if (!instance_loaded) { + instance = FileSystem{ + .allocator = allocator, + .top_level_dir = _top_level_dir, + .fs = Implementation.init( + allocator, + _top_level_dir, + ), + // .stats = std.StringHashMap(Stat).init(allocator), + .dirname_store = DirnameStore.init(allocator), + .filename_store = FilenameStore.init(allocator), + }; + instance_loaded = true; + + instance.fs.parent_fs = &instance; + _ = DirEntry.EntryStore.init(allocator); + } - instance.fs.parent_fs = &instance; - _ = DirEntry.EntryStore.init(allocator); return &instance; } @@ -188,7 +193,7 @@ pub const FileSystem = struct { }, } - for (entry.name) |c, i| { + for (name) |c, i| { name[i] = std.ascii.toLower(c); } diff --git a/src/hash_map.zig b/src/hash_map.zig index 431ea3611..73d3d9f98 100644 --- a/src/hash_map.zig +++ b/src/hash_map.zig @@ -69,18 +69,18 @@ pub fn StringHashMapUnmanaged(comptime V: type) type { return HashMapUnmanaged([]const u8, V, hashString, eqlString, default_max_load_percentage); } -// ❯ hyperfine "./esdev.stringEqlNoPtrCheck --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --public-url=https://hello.com/" "./esdev-fd-rel-hash --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --public-url=https://hello.com/" --min-runs=50 -// Benchmark #1: ./esdev.stringEqlNoPtrCheck --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --public-url=https://hello.com/ +// ❯ hyperfine "./esdev.stringEqlNoPtrCheck --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --origin=https://hello.com/" "./esdev-fd-rel-hash --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --origin=https://hello.com/" --min-runs=50 +// Benchmark #1: ./esdev.stringEqlNoPtrCheck --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --origin=https://hello.com/ // Time (mean ± σ): 251.5 ms ± 7.8 ms [User: 110.0 ms, System: 135.7 ms] // Range (min … max): 239.0 ms … 281.1 ms 50 runs -// Benchmark #2: ./esdev-fd-rel-hash --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --public-url=https://hello.com/ +// Benchmark #2: ./esdev-fd-rel-hash --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --origin=https://hello.com/ // Time (mean ± σ): 249.3 ms ± 8.3 ms [User: 110.8 ms, System: 134.0 ms] // Range (min … max): 239.8 ms … 288.7 ms 50 runs // Summary -// './esdev-fd-rel-hash --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --public-url=https://hello.com/' ran -// 1.01 ± 0.05 times faster than './esdev.stringEqlNoPtrCheck --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --public-url=https://hello.com/' +// './esdev-fd-rel-hash --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --origin=https://hello.com/' ran +// 1.01 ± 0.05 times faster than './esdev.stringEqlNoPtrCheck --resolve=dev --cwd /Users/jarred/Code/esdev/bench/rome/src entry --platform=node --outdir=/Users/jarred/Code/esdev/bench/rome/src/out --origin=https://hello.com/' pub fn eqlString(a: []const u8, b: []const u8) bool { return mem.eql(u8, a, b); } diff --git a/src/http.zig b/src/http.zig index 3bd4a98f1..0cdabf6b4 100644 --- a/src/http.zig +++ b/src/http.zig @@ -134,8 +134,8 @@ pub const RequestContext = struct { pub fn getFullURL(this: *RequestContext) [:0]const u8 { if (this.full_url.len == 0) { - if (this.bundler.options.public_url.len > 0) { - this.full_url = std.fmt.allocPrintZ(this.allocator, "{s}{s}", .{ this.bundler.options.public_url, this.request.path }) catch unreachable; + if (this.bundler.options.origin.len > 0) { + this.full_url = std.fmt.allocPrintZ(this.allocator, "{s}{s}", .{ this.bundler.options.origin, this.request.path }) catch unreachable; } else { this.full_url = this.allocator.dupeZ(u8, this.request.path) catch unreachable; } @@ -735,16 +735,35 @@ pub const RequestContext = struct { std.debug.assert(JavaScript.VirtualMachine.vm_loaded); javascript_vm = vm; - const boot = handler.framework.entry_point; + const boot = vm.bundler.options.framework.?.server; std.debug.assert(boot.len > 0); defer vm.deinit(); vm.watcher = handler.watcher; - var resolved_entry_point = try vm.bundler.resolver.resolve( - std.fs.path.dirname(boot) orelse vm.bundler.fs.top_level_dir, - vm.bundler.normalizeEntryPointPath(boot), - .entry_point, - ); - var load_result = try vm.loadEntryPoint(resolved_entry_point.path_pair.primary.text); + var entry_point = boot; + if (!std.fs.path.isAbsolute(entry_point)) { + const resolved_entry_point = try vm.bundler.resolver.resolve( + std.fs.path.dirname(boot) orelse vm.bundler.fs.top_level_dir, + vm.bundler.normalizeEntryPointPath(boot), + .entry_point, + ); + entry_point = resolved_entry_point.path_pair.primary.text; + } + + var load_result = vm.loadEntryPoint( + entry_point, + ) catch |err| { + Output.prettyErrorln( + "<r>JavaScript VM failed to start.\n<red>{s}:<r> while loading <r><b>\"\"", + .{ @errorName(err), entry_point }, + ); + + if (channel.tryReadItem() catch null) |item| { + item.ctx.sendInternalError(error.JSFailedToStart) catch {}; + item.ctx.arena.deinit(); + } + return; + }; + switch (load_result.status(vm.global.vm())) { JSPromise.Status.Fulfilled => {}, else => { @@ -766,6 +785,10 @@ pub const RequestContext = struct { if (vm.event_listeners.count() == 0) { Output.prettyErrorln("<r><red>error<r>: Framework didn't run <b><cyan>addEventListener(\"fetch\", callback)<r>, which means it can't accept HTTP requests.\nShutting down JS.", .{}); + if (channel.tryReadItem() catch null) |item| { + item.ctx.sendInternalError(error.JSFailedToStart) catch {}; + item.ctx.arena.deinit(); + } return; } @@ -814,15 +837,30 @@ pub const RequestContext = struct { if (!has_loaded_channel) { has_loaded_channel = true; channel = Channel.init(); - try JavaScriptHandler.spawnThread( - HandlerThread{ - .args = server.transform_options, - .framework = server.bundler.options.framework.?, - .existing_bundle = server.bundler.options.node_modules_bundle, - .log = &server.log, - .watcher = server.watcher, - }, - ); + var transform_options = server.transform_options; + if (server.transform_options.node_modules_bundle_path_server) |bundle_path| { + transform_options.node_modules_bundle_path = bundle_path; + transform_options.node_modules_bundle_path_server = null; + try JavaScriptHandler.spawnThread( + HandlerThread{ + .args = transform_options, + .framework = server.bundler.options.framework.?, + .existing_bundle = null, + .log = &server.log, + .watcher = server.watcher, + }, + ); + } else { + try JavaScriptHandler.spawnThread( + HandlerThread{ + .args = server.transform_options, + .framework = server.bundler.options.framework.?, + .existing_bundle = server.bundler.options.node_modules_bundle, + .log = &server.log, + .watcher = server.watcher, + }, + ); + } } defer ctx.controlled = true; diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig index 5c2b630e3..4902c731a 100644 --- a/src/javascript/jsc/base.zig +++ b/src/javascript/jsc/base.zig @@ -185,6 +185,8 @@ pub const To = struct { pub const Properties = struct { pub const UTF8 = struct { + pub var filepath: string = "filepath"; + pub const module: string = "module"; pub const globalThis: string = "globalThis"; pub const exports: string = "exports"; @@ -245,6 +247,8 @@ pub const Properties = struct { }; pub const Refs = struct { + pub var filepath: js.JSStringRef = undefined; + pub var module: js.JSStringRef = undefined; pub var globalThis: js.JSStringRef = undefined; pub var exports: js.JSStringRef = undefined; @@ -283,7 +287,7 @@ pub const Properties = struct { @field(UTF8, name).len, ); - if (isDebug) { + if (comptime isDebug) { std.debug.assert( js.JSStringIsEqualToString(@field(Refs, name), @field(UTF8, name).ptr, @field(UTF8, name).len), ); diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp index 2a26e44cb..fbe3c22ae 100644 --- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp +++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp @@ -290,16 +290,26 @@ JSC::JSObject *GlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObje JSValue key, JSModuleRecord *record, JSValue val) { - return nullptr; - // auto res = Zig__GlobalObject__createImportMetaProperties( - // globalObject, - // loader, - // JSValue::encode(key), - // record, - // JSValue::encode(val) - // ); - - // return JSValue::decode(res).getObject(); + + ZigString specifier = Zig::toZigString(key, globalObject); + JSC::VM &vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSC::JSObject *metaProperties = + JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure()); + RETURN_IF_EXCEPTION(scope, nullptr); + + metaProperties->putDirect(vm, Identifier::fromString(vm, "filePath"), key); + RETURN_IF_EXCEPTION(scope, nullptr); + + // metaProperties->putDirect(vm, Identifier::fromString(vm, "resolve"), + // globalObject->globalThis() + // ->get(vm, Identifier::fromString("Wundle")) + // .getObject() + // ->get(vm, Identifier::fromString("resolve"))); ); + // RETURN_IF_EXCEPTION(scope, nullptr); + + return metaProperties; } JSC::JSValue GlobalObject::moduleLoaderEvaluate(JSGlobalObject *globalObject, diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp index 33aded945..924a43193 100644 --- a/src/javascript/jsc/bindings/bindings.cpp +++ b/src/javascript/jsc/bindings/bindings.cpp @@ -401,6 +401,17 @@ JSC__JSValue ZigString__toValue(ZigString arg0, JSC__JSGlobalObject *arg1) { return JSC::JSValue::encode(JSC::JSValue(JSC::jsOwnedString(arg1->vm(), Zig::toString(arg0)))); } +JSC__JSValue ZigString__toValueGC(ZigString arg0, JSC__JSGlobalObject *arg1) { + return JSC::JSValue::encode( + JSC::JSValue(JSC::jsMakeNontrivialString(arg1->vm(), Zig::toString(arg0)))); +} + +void JSC__JSValue__toZigString(JSC__JSValue JSValue0, ZigString *arg1, JSC__JSGlobalObject *arg2) { + JSC::JSValue value = JSC::JSValue::decode(JSValue0); + auto str = value.toWTFString(arg2); + arg1->ptr = str.characters8(); + arg1->len = str.length(); +} JSC__JSValue ZigString__toErrorInstance(const ZigString *str, JSC__JSGlobalObject *globalObject) { JSC::VM &vm = globalObject->vm(); diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig index 07f177cb1..28e34717d 100644 --- a/src/javascript/jsc/bindings/bindings.zig +++ b/src/javascript/jsc/bindings/bindings.zig @@ -110,6 +110,10 @@ pub const ZigString = extern struct { return shim.cppFn("toValue", .{ this, global }); } + pub fn toValueGC(this: ZigString, global: *JSGlobalObject) JSValue { + return shim.cppFn("toValueGC", .{ this, global }); + } + pub fn toJSStringRef(this: *const ZigString) C_API.JSStringRef { return C_API.JSStringCreateStatic(this.ptr, this.len); } @@ -120,6 +124,7 @@ pub const ZigString = extern struct { pub const Extern = [_][]const u8{ "toValue", + "toValueGC", "toErrorInstance", }; }; @@ -1319,6 +1324,16 @@ pub const JSValue = enum(i64) { return cppFn("toZigException", .{ this, global, exception }); } + pub fn toZigString(this: JSValue, out: *ZigString, global: *JSGlobalObject) void { + return cppFn("toZigString", .{ this, out, global }); + } + + pub inline fn getZigString(this: JSValue, global: *JSGlobalObject) ZigString { + var str = ZigString.init(""); + this.toZigString(&str, global); + return str; + } + // On exception, this returns the empty string. pub fn toString(this: JSValue, globalThis: *JSGlobalObject) *JSString { return cppFn("toString", .{ this, globalThis }); @@ -1415,7 +1430,7 @@ pub const JSValue = enum(i64) { return @intToPtr(*c_void, @intCast(usize, @enumToInt(this))); } - pub const Extern = [_][]const u8{ "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "get", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt32", "jsNumberFromInt64", "jsNumberFromUint64", "isUndefined", "isNull", "isUndefinedOrNull", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" }; + pub const Extern = [_][]const u8{ "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "get", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt32", "jsNumberFromInt64", "jsNumberFromUint64", "isUndefined", "isNull", "isUndefinedOrNull", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" }; }; pub const PropertyName = extern struct { diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h index 5f3781646..50fad777b 100644 --- a/src/javascript/jsc/bindings/headers-cpp.h +++ b/src/javascript/jsc/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1628394202 +//-- AUTOGENERATED FILE -- 1628467440 // clang-format off #pragma once diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h index 95e6c6d47..ed9678c65 100644 --- a/src/javascript/jsc/bindings/headers.h +++ b/src/javascript/jsc/bindings/headers.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1628394202 +//-- AUTOGENERATED FILE -- 1628467440 // clang-format: off #pragma once @@ -239,6 +239,7 @@ CPP_DECL void JSC__JSObject__putDirect(JSC__JSObject* arg0, JSC__JSGlobalObject* CPP_DECL void JSC__JSObject__putRecord(JSC__JSObject* arg0, JSC__JSGlobalObject* arg1, ZigString* arg2, ZigString* arg3, size_t arg4); CPP_DECL JSC__JSValue ZigString__toErrorInstance(const ZigString* arg0, JSC__JSGlobalObject* arg1); CPP_DECL JSC__JSValue ZigString__toValue(ZigString arg0, JSC__JSGlobalObject* arg1); +CPP_DECL JSC__JSValue ZigString__toValueGC(ZigString arg0, JSC__JSGlobalObject* arg1); #pragma mark - JSC::JSCell @@ -467,6 +468,7 @@ CPP_DECL JSC__JSString* JSC__JSValue__toString(JSC__JSValue JSValue0, JSC__JSGlo CPP_DECL JSC__JSString* JSC__JSValue__toStringOrNull(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL bWTF__String JSC__JSValue__toWTFString(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL void JSC__JSValue__toZigException(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigException* arg2); +CPP_DECL void JSC__JSValue__toZigString(JSC__JSValue JSValue0, ZigString* arg1, JSC__JSGlobalObject* arg2); #pragma mark - JSC::PropertyName diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig index 98b2b505f..10a5dd526 100644 --- a/src/javascript/jsc/bindings/headers.zig +++ b/src/javascript/jsc/bindings/headers.zig @@ -105,6 +105,7 @@ pub extern fn JSC__JSObject__putDirect(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__J pub extern fn JSC__JSObject__putRecord(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void; pub extern fn ZigString__toErrorInstance(arg0: [*c]const ZigString, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue; pub extern fn ZigString__toValue(arg0: ZigString, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue; +pub extern fn ZigString__toValueGC(arg0: ZigString, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue; pub extern fn JSC__JSCell__getObject(arg0: [*c]JSC__JSCell) [*c]JSC__JSObject; pub extern fn JSC__JSCell__getString(arg0: [*c]JSC__JSCell, arg1: [*c]JSC__JSGlobalObject) bWTF__String; pub extern fn JSC__JSCell__getType(arg0: [*c]JSC__JSCell) u8; @@ -290,6 +291,7 @@ pub extern fn JSC__JSValue__toString(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGl pub extern fn JSC__JSValue__toStringOrNull(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) [*c]JSC__JSString; pub extern fn JSC__JSValue__toWTFString(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) bWTF__String; pub extern fn JSC__JSValue__toZigException(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]ZigException) void; +pub extern fn JSC__JSValue__toZigString(JSValue0: JSC__JSValue, arg1: [*c]ZigString, arg2: [*c]JSC__JSGlobalObject) void; pub extern fn JSC__PropertyName__eqlToIdentifier(arg0: [*c]JSC__PropertyName, arg1: [*c]const JSC__Identifier) bool; pub extern fn JSC__PropertyName__eqlToPropertyName(arg0: [*c]JSC__PropertyName, arg1: [*c]const JSC__PropertyName) bool; pub extern fn JSC__PropertyName__publicName(arg0: [*c]JSC__PropertyName) [*c]const WTF__StringImpl; diff --git a/src/javascript/jsc/config.zig b/src/javascript/jsc/config.zig index d773c60e8..601ea86a6 100644 --- a/src/javascript/jsc/config.zig +++ b/src/javascript/jsc/config.zig @@ -24,15 +24,19 @@ pub const DefaultSpeedyDefines = struct { }; }; -pub fn configureTransformOptionsForSpeedy(allocator: *std.mem.Allocator, _args: Api.TransformOptions) !Api.TransformOptions { +pub fn configureTransformOptionsForSpeedyVM(allocator: *std.mem.Allocator, _args: Api.TransformOptions) !Api.TransformOptions { var args = _args; - args.platform = Api.Platform.speedy; args.serve = false; args.write = false; args.resolve = Api.ResolveMode.lazy; args.generate_node_module_bundle = false; + return try configureTransformOptionsForSpeedy(allocator, args); +} +pub fn configureTransformOptionsForSpeedy(allocator: *std.mem.Allocator, _args: Api.TransformOptions) !Api.TransformOptions { + var args = _args; + args.platform = Api.Platform.speedy; // We inline process.env.* at bundle time but process.env is a proxy object which will otherwise return undefined. var env_map = try getNodeEnvMap(allocator); diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig index 9bfcfa21c..521d56486 100644 --- a/src/javascript/jsc/javascript.zig +++ b/src/javascript/jsc/javascript.zig @@ -33,14 +33,37 @@ pub const GlobalClasses = [_]type{ }; pub const Wundle = struct { - top_level_dir: string, - threadlocal var css_imports_list_strings: [512]ZigString = undefined; threadlocal var css_imports_list: [512]Api.StringPointer = undefined; threadlocal var css_imports_list_tail: u16 = 0; threadlocal var css_imports_buf: std.ArrayList(u8) = undefined; threadlocal var css_imports_buf_loaded: bool = false; + pub fn onImportCSS( + resolve_result: *const Resolver.Result, + import_record: *ImportRecord, + source_dir: string, + ) void { + if (!css_imports_buf_loaded) { + css_imports_buf = std.ArrayList(u8).initCapacity( + VirtualMachine.vm.allocator, + import_record.path.text.len, + ) catch unreachable; + css_imports_buf_loaded = true; + } + + var writer = css_imports_buf.writer(); + const offset = css_imports_buf.items.len; + css_imports_list[css_imports_list_tail] = .{ + .offset = @truncate(u32, offset), + .length = 0, + }; + getPublicPath(resolve_result.path_pair.primary.text, @TypeOf(writer), writer); + const length = css_imports_buf.items.len - offset; + css_imports_list[css_imports_list_tail].length = @truncate(u32, length); + css_imports_list_tail += 1; + } + pub fn flushCSSImports() void { if (css_imports_buf_loaded) { css_imports_buf.clearRetainingCapacity(); @@ -57,6 +80,36 @@ pub const Wundle = struct { return css_imports_list_strings[0..tail]; } + pub fn getCWD( + this: void, + ctx: js.JSContextRef, + thisObject: js.JSValueRef, + prop: js.JSStringRef, + exception: js.ExceptionRef, + ) js.JSValueRef { + return ZigString.init(VirtualMachine.vm.bundler.fs.top_level_dir).toValue(VirtualMachine.vm.global).asRef(); + } + + pub fn getOrigin( + this: void, + ctx: js.JSContextRef, + thisObject: js.JSValueRef, + prop: js.JSStringRef, + exception: js.ExceptionRef, + ) js.JSValueRef { + return ZigString.init(VirtualMachine.vm.bundler.options.origin).toValue(VirtualMachine.vm.global).asRef(); + } + + pub fn getMain( + this: void, + ctx: js.JSContextRef, + thisObject: js.JSValueRef, + prop: js.JSStringRef, + exception: js.ExceptionRef, + ) js.JSValueRef { + return ZigString.init(VirtualMachine.vm.main).toValue(VirtualMachine.vm.global).asRef(); + } + pub fn getImportedStyles( this: void, ctx: js.JSContextRef, @@ -74,38 +127,13 @@ pub const Wundle = struct { return JSValue.createStringArray(VirtualMachine.vm.global, styles.ptr, styles.len).asRef(); } - pub fn onImportCSS( - resolve_result: *const Resolver.Result, - import_record: *ImportRecord, - source_dir: string, - ) void { - if (!css_imports_buf_loaded) { - css_imports_buf = std.ArrayList(u8).initCapacity( - VirtualMachine.vm.allocator, - import_record.path.text.len, - ) catch unreachable; - css_imports_buf_loaded = true; - } - - var writer = css_imports_buf.writer(); - const offset = css_imports_buf.items.len; - css_imports_list[css_imports_list_tail] = .{ - .offset = @truncate(u32, offset), - .length = 0, - }; - getPublicPath(resolve_result.path_pair.primary.text, @TypeOf(writer), writer); - const length = css_imports_buf.items.len - offset; - css_imports_list[css_imports_list_tail].length = @truncate(u32, length); - css_imports_list_tail += 1; - } - pub fn getPublicPath(to: string, comptime Writer: type, writer: Writer) void { const relative_path = VirtualMachine.vm.bundler.fs.relativeTo(to); - if (VirtualMachine.vm.bundler.options.public_url.len > 0) { + if (VirtualMachine.vm.bundler.options.origin.len > 0) { writer.print( "{s}/{s}", .{ - std.mem.trimRight(u8, VirtualMachine.vm.bundler.options.public_url, "/"), + std.mem.trimRight(u8, VirtualMachine.vm.bundler.options.origin, "/"), std.mem.trimLeft(u8, relative_path, "/"), }, ) catch unreachable; @@ -141,6 +169,18 @@ pub const Wundle = struct { }, .{ .Route = Router.Instance.GetClass(void){}, + .main = .{ + .get = getMain, + .ts = d.ts{ .name = "main", .@"return" = "string" }, + }, + .cwd = .{ + .get = getCWD, + .ts = d.ts{ .name = "cwd", .@"return" = "string" }, + }, + .origin = .{ + .get = getOrigin, + .ts = d.ts{ .name = "origin", .@"return" = "string" }, + }, }, ); }; @@ -165,6 +205,8 @@ pub const VirtualMachine = struct { require_cache: RequireCacheType, log: *logger.Log, event_listeners: EventListenerMixin.Map, + main: string = "", + pub var vm_loaded = false; pub var vm: *VirtualMachine = undefined; @@ -187,7 +229,7 @@ pub const VirtualMachine = struct { const bundler = try Bundler.init( allocator, log, - try configureTransformOptionsForSpeedy(allocator, _args), + try configureTransformOptionsForSpeedyVM(allocator, _args), existing_bundle, ); VirtualMachine.vm.* = VirtualMachine{ @@ -202,6 +244,7 @@ pub const VirtualMachine = struct { }; VirtualMachine.vm.bundler.configureLinker(); + try VirtualMachine.vm.bundler.configureFramework(); if (_args.serve orelse false) { VirtualMachine.vm.bundler.linker.onImportCSS = Wundle.onImportCSS; @@ -559,6 +602,7 @@ pub const VirtualMachine = struct { pub fn loadEntryPoint(this: *VirtualMachine, entry_point: string) !*JSInternalPromise { var path = this.bundler.normalizeEntryPointPath(entry_point); + this.main = entry_point; var promise = JSModuleLoader.loadAndEvaluateModule(this.global, ZigString.init(path)); this.global.vm().drainMicrotasks(); diff --git a/src/js_ast.zig b/src/js_ast.zig index 1890f972f..3f032e075 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -1946,6 +1946,27 @@ pub const Expr = struct { return null; } + pub const ArrayIterator = struct { + array: *const E.Array, + index: u32, + + pub fn next(this: *ArrayIterator) ?Expr { + if (this.index >= this.array.items.len) { + return null; + } + defer this.index += 1; + return this.array.items[this.index]; + } + }; + + pub fn asArray(expr: *const Expr) ?ArrayIterator { + if (std.meta.activeTag(expr.data) != .e_array) return null; + const array = expr.data.e_array; + if (array.items.len == 0 or @ptrToInt(array.items.ptr) == 0) return null; + + return ArrayIterator{ .array = array, .index = 0 }; + } + pub fn asString(expr: *const Expr, allocator: *std.mem.Allocator) ?string { if (std.meta.activeTag(expr.data) != .e_string) return null; diff --git a/src/linker.zig b/src/linker.zig index 0c68d53f1..518c3d43c 100644 --- a/src/linker.zig +++ b/src/linker.zig @@ -536,7 +536,7 @@ pub fn NewLinker(comptime BundlerType: type) type { linker.allocator, "{s}{s}/{s}{s}", .{ - linker.options.public_url, + linker.options.origin, dirname, basename, absolute_pathname.ext, @@ -549,7 +549,7 @@ pub fn NewLinker(comptime BundlerType: type) type { linker.allocator, "{s}{s}{s}{s}", .{ - linker.options.public_url, + linker.options.origin, dirname, basename, absolute_pathname.ext, diff --git a/src/main_javascript.zig b/src/main_javascript.zig index f5976e304..8529d5584 100644 --- a/src/main_javascript.zig +++ b/src/main_javascript.zig @@ -144,7 +144,7 @@ pub const Cli = struct { clap.parseParam("-e, --external <STR>... Exclude module from transpilation (can use * wildcards). ex: -e react") catch unreachable, clap.parseParam("-i, --inject <STR>... Inject module at the top of every file") catch unreachable, clap.parseParam("--cwd <STR> Absolute path to resolve entry points from. Defaults to cwd") catch unreachable, - clap.parseParam("--public-url <STR> Rewrite import paths to start with --public-url. Useful for web browsers.") catch unreachable, + clap.parseParam("--origin <STR> Rewrite import paths to start with --origin. Useful for web browsers.") catch unreachable, clap.parseParam("--serve Start a local dev server. This also sets resolve to \"lazy\".") catch unreachable, clap.parseParam("--public-dir <STR> Top-level directory for .html files, fonts, images, or anything external. Only relevant with --serve. Defaults to \"<cwd>/public\", to match create-react-app and Next.js") catch unreachable, clap.parseParam("--jsx-factory <STR> Changes the function called when compiling JSX elements using the classic JSX runtime") catch unreachable, @@ -180,7 +180,7 @@ pub const Cli = struct { var cwd_paths = [_]string{args.option("--cwd") orelse try std.process.getCwdAlloc(allocator)}; var cwd = try std.fs.path.resolve(allocator, &cwd_paths); var tsconfig_override = if (args.option("--tsconfig-override")) |ts| (Arguments.readFile(allocator, cwd, ts) catch |err| fileReadError(err, stderr, ts, "tsconfig.json")) else null; - var public_url = args.option("--public-url"); + var origin = args.option("--origin"); var defines_tuple = try DefineColonList.resolve(allocator, args.options("--define")); var loader_tuple = try LoaderColonList.resolve(allocator, args.options("--define")); @@ -322,7 +322,7 @@ pub const Cli = struct { .external = externals, .absolute_working_dir = cwd, .tsconfig_override = tsconfig_override, - .public_url = public_url, + .origin = origin, .define = .{ .keys = define_keys, .values = define_values, @@ -386,7 +386,9 @@ pub const Cli = struct { var log = logger.Log.init(this.allocator); var vm = try VirtualMachine.init(this.allocator, this.args, null, &log); - var promise = try vm.loadEntryPoint(vm.bundler.options.entry_points[0]); + var promise = try vm.loadEntryPoint( + vm.bundler.options.entry_points[0], + ); if (promise.status(vm.global.vm()) == js.JSPromise.Status.Rejected) { vm.defaultErrorHandler(promise.result(vm.global.vm())); } diff --git a/src/options.zig b/src/options.zig index c7885aa7f..64bb5912d 100644 --- a/src/options.zig +++ b/src/options.zig @@ -610,7 +610,7 @@ pub const BundleOptions = struct { hot_module_reloading: bool = false, inject: ?[]string = null, - public_url: string = "", + origin: string = "", public_dir: string = "public", public_dir_enabled: bool = true, output_dir: string = "", @@ -623,6 +623,7 @@ pub const BundleOptions = struct { preserve_extensions: bool = false, timings: Timings = Timings{}, node_modules_bundle: ?*NodeModuleBundle = null, + production: bool = false, append_package_version_in_query_string: bool = false, @@ -670,9 +671,9 @@ pub const BundleOptions = struct { .out_extensions = undefined, }; - if (transform.public_url) |public_url| { + if (transform.origin) |origin| { opts.import_path_format = ImportPathFormat.absolute_url; - opts.public_url = public_url; + opts.origin = origin; } if (transform.jsx) |jsx| { @@ -780,7 +781,7 @@ pub const BundleOptions = struct { opts.node_modules_bundle = node_mods; const pretty_path = fs.relativeTo(transform.node_modules_bundle_path.?); opts.node_modules_bundle_url = try std.fmt.allocPrint(allocator, "{s}{s}", .{ - opts.public_url, + opts.origin, pretty_path, }); } else if (transform.node_modules_bundle_path) |bundle_path| { @@ -799,15 +800,15 @@ pub const BundleOptions = struct { var node_module_bundle = try allocator.create(NodeModuleBundle); node_module_bundle.* = bundle; opts.node_modules_bundle = node_module_bundle; - if (opts.public_url.len > 0) { + if (opts.origin.len > 0) { var relative = node_module_bundle.bundle.import_from_name; if (relative[0] == std.fs.path.sep) { relative = relative[1..]; } - const buf_size = opts.public_url.len + relative.len + pretty_path.len; + const buf_size = opts.origin.len + relative.len + pretty_path.len; var buf = try allocator.alloc(u8, buf_size); - opts.node_modules_bundle_url = try std.fmt.bufPrint(buf, "{s}{s}", .{ opts.public_url, relative }); + opts.node_modules_bundle_url = try std.fmt.bufPrint(buf, "{s}{s}", .{ opts.origin, relative }); opts.node_modules_bundle_pretty_path = buf[opts.node_modules_bundle_url.len..]; std.mem.copy( u8, @@ -829,6 +830,17 @@ pub const BundleOptions = struct { }, ); Output.flush(); + if (opts.framework == null) { + if (node_module_bundle.container.framework) |loaded_framework| { + opts.framework = Framework.fromLoadedFramework(loaded_framework); + } + } + + if (opts.route_config == null) { + if (node_module_bundle.container.routes) |routes| { + opts.route_config = RouteConfig.fromLoadedRoutes(routes); + } + } } else |err| { Output.disableBuffering(); Output.prettyErrorln( @@ -870,7 +882,7 @@ pub const TransformOptions = struct { jsx: ?JSX.Pragma, react_fast_refresh: bool = false, inject: ?[]string = null, - public_url: string = "", + origin: string = "", preserve_symlinks: bool = false, entry_point: Fs.File, resolve_paths: bool = false, @@ -1113,35 +1125,119 @@ pub const TransformResult = struct { }; pub const Framework = struct { - entry_point: string, + client: string, + server: string, + package: string = "", + development: bool = true, + resolved: bool = false, + from_bundle: bool = false, + + fn normalizedPath(allocator: *std.mem.Allocator, toplevel_path: string, path: string) !string { + std.debug.assert(std.fs.path.isAbsolute(path)); + var str = path; + if (strings.indexOf(str, toplevel_path)) |top| { + str = str[top + toplevel_path.len ..]; + } + + // if it *was* a node_module path, we don't do any allocation, we just keep it as a package path + if (strings.indexOf(str, "node_modules" ++ std.fs.path.sep_str)) |node_module_i| { + return str[node_module_i + "node_modules".len + 1 ..]; + // otherwise, we allocate a new string and copy the path into it with a leading "./" + + } else { + var out = try allocator.alloc(u8, str.len + 2); + out[0] = '.'; + out[1] = '/'; + std.mem.copy(u8, out[2..], str); + return out; + } + } + + pub fn fromLoadedFramework(loaded: Api.LoadedFramework) Framework { + const client = if (loaded.client) loaded.entry_point else ""; + const server = if (!loaded.client) loaded.entry_point else ""; + return Framework{ + .client = client, + .server = server, + .package = loaded.package, + .development = loaded.development, + .from_bundle = true, + }; + } + + pub fn toAPI(this: *const Framework, allocator: *std.mem.Allocator, toplevel_path: string, comptime client: bool) ?Api.LoadedFramework { + if (comptime client) { + if (this.client.len > 0) { + return Api.LoadedFramework{ + .entry_point = normalizedPath(allocator, toplevel_path, this.client) catch unreachable, + .package = this.package, + .development = this.development, + .client = true, + }; + } + } else { + if (this.server.len > 0) { + return Api.LoadedFramework{ + .entry_point = normalizedPath(allocator, toplevel_path, this.server) catch unreachable, + .package = this.package, + .development = this.development, + .client = false, + }; + } + } + + return null; + } + + pub fn needsResolveFromPackage(this: *const Framework) bool { + return !this.resolved and this.package.len > 0; + } pub fn fromApi( transform: Api.FrameworkConfig, ) !Framework { return Framework{ - .entry_point = transform.entry_point.?, + .client = transform.client orelse "", + .server = transform.server orelse "", + .package = transform.package orelse "", + .development = transform.development orelse true, + .resolved = false, }; } }; pub const RouteConfig = struct { /// - dir: string, + dir: string = "", // TODO: do we need a separate list for data-only extensions? // e.g. /foo.json just to get the data for the route, without rendering the html // I think it's fine to hardcode as .json for now, but if I personally were writing a framework // I would consider using a custom binary format to minimize request size // maybe like CBOR - extensions: []const string, + extensions: []const string = &[_][]const string{}, + + pub fn toAPI(this: *const RouteConfig) Api.LoadedRouteConfig { + return .{ .dir = this.dir, .extensions = this.extensions }; + } pub const DefaultDir = "pages"; pub const DefaultExtensions = [_]string{ "tsx", "ts", "mjs", "jsx", "js" }; - - pub fn fromApi(router_: Api.RouteConfig, allocator: *std.mem.Allocator) !RouteConfig { - var router = RouteConfig{ + pub inline fn zero() RouteConfig { + return RouteConfig{ .dir = DefaultDir, .extensions = std.mem.span(&DefaultExtensions), }; + } + + pub fn fromLoadedRoutes(loaded: Api.LoadedRouteConfig) RouteConfig { + return RouteConfig{ + .extensions = loaded.extensions, + .dir = loaded.dir, + }; + } + + pub fn fromApi(router_: Api.RouteConfig, allocator: *std.mem.Allocator) !RouteConfig { + var router = zero(); var router_dir: string = std.mem.trimRight(u8, router_.dir orelse "", "/\\"); diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig index c0faeda2e..07d58ff6f 100644 --- a/src/resolver/package_json.zig +++ b/src/resolver/package_json.zig @@ -1,4 +1,5 @@ usingnamespace @import("../global.zig"); +const Api = @import("../api/schema.zig").Api; const std = @import("std"); const options = @import("../options.zig"); const log = @import("../logger.zig"); @@ -12,7 +13,20 @@ const resolver = @import("./resolver.zig"); const MainFieldMap = std.StringHashMap(string); const BrowserMap = std.StringHashMap(string); threadlocal var hashed_buf: [2048]u8 = undefined; + pub const PackageJSON = struct { + pub const LoadFramework = enum { + none, + development, + production, + }; + + pub const FrameworkRouterPair = struct { + framework: *options.Framework, + router: *options.RouteConfig, + loaded_routes: bool = false, + }; + name: string = "", source: logger.Source, main_fields: MainFieldMap, @@ -47,6 +61,97 @@ pub const PackageJSON = struct { // browser_map: BrowserMap, + fn loadFrameworkExpression(framework: *options.Framework, json: js_ast.Expr, allocator: *std.mem.Allocator) bool { + if (json.asProperty("client")) |client| { + if (client.expr.asString(allocator)) |str| { + if (str.len > 0) { + framework.client = str; + } + } + } + + if (json.asProperty("server")) |server| { + if (server.expr.asString(allocator)) |str| { + if (str.len > 0) { + framework.server = str; + } + } + } + + return framework.client.len > 0; + } + + pub fn loadFrameworkWithPreference(package_json: *const PackageJSON, pair: *FrameworkRouterPair, json: js_ast.Expr, allocator: *std.mem.Allocator, comptime load_framework: LoadFramework) void { + const framework_object = json.asProperty("framework") orelse return; + + if (framework_object.expr.asProperty("router")) |router| { + if (router.expr.asProperty("dir")) |route_dir| { + if (route_dir.expr.asString(allocator)) |str| { + if (str.len > 0) { + pair.router.dir = str; + pair.loaded_routes = true; + } + } + } + + if (router.expr.asProperty("extensions")) |extensions_expr| { + if (extensions_expr.expr.asArray()) |*array| { + const count = array.array.items.len; + var valid_count: usize = 0; + + while (array.next()) |expr| { + if (expr.data != .e_string) continue; + const e_str: *const js_ast.E.String = expr.data.e_string; + if (e_str.utf8.len == 0 or e_str.utf8[0] != '.') continue; + valid_count += 1; + } + + if (valid_count > 0) { + var extensions = allocator.alloc(string, valid_count) catch unreachable; + array.index = 0; + var i: usize = 0; + + // We don't need to allocate the strings because we keep the package.json source string in memory + while (array.next()) |expr| { + if (expr.data != .e_string) continue; + const e_str: *const js_ast.E.String = expr.data.e_string; + if (e_str.utf8.len == 0 or e_str.utf8[0] != '.') continue; + extensions[i] = e_str.utf8; + i += 1; + } + } + } + } + } + + switch (comptime load_framework) { + .development => { + if (framework_object.expr.asProperty("development")) |env| { + if (loadFrameworkExpression(pair.framework, env.expr, allocator)) { + pair.framework.package = package_json.name; + pair.framework.development = true; + return; + } + } + }, + .production => { + if (framework_object.expr.asProperty("production")) |env| { + if (loadFrameworkExpression(pair.framework, env.expr, allocator)) { + pair.framework.package = package_json.name; + pair.framework.development = false; + return; + } + } + }, + else => unreachable, + } + + if (loadFrameworkExpression(pair.framework, framework_object.expr, allocator)) { + pair.framework.package = package_json.name; + pair.framework.development = false; + } + } + pub fn parse( comptime ResolverType: type, r: *ResolverType, diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index 5d2ed8aed..cf517498b 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -10,7 +10,7 @@ const TSConfigJSON = @import("./tsconfig_json.zig").TSConfigJSON; const PackageJSON = @import("./package_json.zig").PackageJSON; usingnamespace @import("./data_url.zig"); pub const DirInfo = @import("./dir_info.zig"); - +const Expr = @import("../js_ast.zig").Expr; const Wyhash = std.hash.Wyhash; const hash_map_v2 = @import("../hash_map_v2.zig"); @@ -249,6 +249,9 @@ pub const LoadResult = struct { dirname_fd: StoredFileDescriptorType = 0, }; +// This is a global so even if multiple resolvers are created, the mutex will still work +var resolver_Mutex: Mutex = undefined; +var resolver_Mutex_loaded: bool = false; // TODO: // - Fix "browser" field mapping // - Consider removing the string list abstraction? @@ -306,7 +309,7 @@ pub fn NewResolver(cache_files: bool) type { // reducing parallelism in the resolver helps the rest of the bundler go // faster. I'm not sure why this is but please don't change this unless you // do a lot of testing with various benchmarks and there aren't any regressions. - mutex: Mutex, + mutex: *Mutex, // This cache maps a directory path to information about that directory and // all parent directories @@ -318,10 +321,14 @@ pub fn NewResolver(cache_files: bool) type { _fs: *Fs.FileSystem, opts: options.BundleOptions, ) ThisResolver { + if (!resolver_Mutex_loaded) { + resolver_Mutex = Mutex.init(); + resolver_Mutex_loaded = true; + } return ThisResolver{ .allocator = allocator, .dir_cache = DirInfo.HashMap.init(allocator), - .mutex = Mutex.init(), + .mutex = &resolver_Mutex, .caches = CacheSet.init(allocator), .opts = opts, .fs = _fs, @@ -356,6 +363,48 @@ pub fn NewResolver(cache_files: bool) type { } var tracing_start: i128 = if (FeatureFlags.tracing) 0 else undefined; + pub fn resolveFramework( + r: *ThisResolver, + package: string, + pair: *PackageJSON.FrameworkRouterPair, + comptime preference: PackageJSON.LoadFramework, + ) !void { + + // TODO: make this only parse package.json once + var result = try r.resolve(r.fs.top_level_dir, package, .internal); + // support passing a package.json or path to a package + const pkg: *const PackageJSON = result.package_json orelse r.packageJSONForResolvedNodeModuleWithIgnoreMissingName(&result, true) orelse return error.MissingPackageJSON; + + const json: Expr = (try r.caches.json.parseJSON(r.log, pkg.source, r.allocator)) orelse return error.JSONParseError; + pkg.loadFrameworkWithPreference(pair, json, r.allocator, preference); + const dir = pkg.source.path.name.dirWithTrailingSlash(); + var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + if (pair.framework.client.len > 0) { + var parts = [_]string{ dir, pair.framework.client }; + const abs = r.fs.abs(&parts); + pair.framework.client = try r.allocator.dupe(u8, try std.os.realpath(abs, &buf)); + pair.framework.resolved = true; + } + + if (pair.framework.server.len > 0) { + var parts = [_]string{ dir, pair.framework.server }; + const abs = r.fs.abs(&parts); + pair.framework.server = try r.allocator.dupe(u8, try std.os.realpath(abs, &buf)); + pair.framework.resolved = true; + } + + if (pair.loaded_routes) { + var parts = [_]string{ r.fs.top_level_dir, std.fs.path.sep_str, pair.router.dir }; + const abs = r.fs.join(&parts); + // must end in trailing slash + var realpath = std.os.realpath(abs, &buf) catch return error.RoutesDirNotFound; + var out = try r.allocator.alloc(u8, realpath.len + 1); + std.mem.copy(u8, out, realpath); + out[out.len - 1] = '/'; + pair.router.dir = out; + } + } + threadlocal var relative_abs_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; pub fn resolve(r: *ThisResolver, source_dir: string, import_path: string, kind: ast.ImportKind) !Result { @@ -695,8 +744,15 @@ pub fn NewResolver(cache_files: bool) type { return result; } + pub fn packageJSONForResolvedNodeModule( + r: *ThisResolver, + result: *const Result, + ) ?*const PackageJSON { + return @call(.{ .modifier = .always_inline }, packageJSONForResolvedNodeModuleWithIgnoreMissingName, .{ r, result, true }); + } + // This is a fallback, hopefully not called often. It should be relatively quick because everything should be in the cache. - pub fn packageJSONForResolvedNodeModule(r: *ThisResolver, result: *const Result) ?*const PackageJSON { + fn packageJSONForResolvedNodeModuleWithIgnoreMissingName(r: *ThisResolver, result: *const Result, comptime ignore_missing_name: bool) ?*const PackageJSON { var current_dir = std.fs.path.dirname(result.path_pair.primary.text); while (current_dir != null) { var dir_info = (r.dirInfoCached(current_dir orelse unreachable) catch null) orelse return null; @@ -705,8 +761,10 @@ pub fn NewResolver(cache_files: bool) type { // if it doesn't have a name, assume it's something just for adjusting the main fields (react-bootstrap does this) // In that case, we really would like the top-level package that you download from NPM // so we ignore any unnamed packages - if (pkg.name.len > 0) { - return pkg; + if (comptime !ignore_missing_name) { + if (pkg.name.len > 0) { + return pkg; + } } } diff --git a/src/router.zig b/src/router.zig index 5ba7c3457..17e265bd5 100644 --- a/src/router.zig +++ b/src/router.zig @@ -114,6 +114,7 @@ pub fn loadRoutes( continue :outer; } } + var abs_parts = [_]string{ entry.dir, entry.base }; if (resolver.readDirInfoIgnoreError(this.fs.abs(&abs_parts))) |_dir_info| { const dir_info: *const DirInfo = _dir_info; diff --git a/src/runtime.version b/src/runtime.version index c31aa4171..1a0bb1fa9 100644 --- a/src/runtime.version +++ b/src/runtime.version @@ -1 +1 @@ -94d347c63505744e
\ No newline at end of file +ca3ca9f44c907d4a
\ No newline at end of file diff --git a/src/runtime/hmr.ts b/src/runtime/hmr.ts index 22b3d1dea..cb9dcbbf4 100644 --- a/src/runtime/hmr.ts +++ b/src/runtime/hmr.ts @@ -836,7 +836,7 @@ var __HMRModule, __FastRefreshModule, __HMRClient; // We must find a React Refresh boundary. This is a module that only exports React components. // If we do not find a React Refresh boundary, we must instead perform a full page reload. for ( - let i = HMRModule.dependencies.graph_used; + let i = HMRModule.dependencies.graph_used - 1; i > this.module_index; i-- ) { diff --git a/src/string_immutable.zig b/src/string_immutable.zig index 7330798b7..5e651fc5d 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -5,27 +5,27 @@ const JavascriptString = @import("ast/base.zig").JavascriptString; usingnamespace @import("string_types.zig"); -pub fn containsChar(self: string, char: u8) bool { +pub inline fn containsChar(self: string, char: u8) bool { return indexOfChar(self, char) != null; } -pub fn contains(self: string, str: string) bool { +pub inline fn contains(self: string, str: string) bool { return std.mem.indexOf(u8, self, str) != null; } -pub fn indexOfChar(self: string, char: u8) ?usize { +pub inline fn indexOfChar(self: string, char: u8) ?usize { return std.mem.indexOfScalar(@TypeOf(char), self, char); } -pub fn lastIndexOfChar(self: string, char: u8) ?usize { +pub inline fn lastIndexOfChar(self: string, char: u8) ?usize { return std.mem.lastIndexOfScalar(u8, self, char); } -pub fn lastIndexOf(self: string, str: string) ?usize { +pub inline fn lastIndexOf(self: string, str: string) ?usize { return std.mem.lastIndexOf(u8, self, str); } -pub fn indexOf(self: string, str: string) ?usize { +pub inline fn indexOf(self: string, str: string) ?usize { return std.mem.indexOf(u8, self, str); } @@ -131,7 +131,7 @@ pub fn eql(self: string, other: anytype) bool { return true; } -pub fn eqlInsensitive(self: string, other: anytype) bool { +pub inline fn eqlInsensitive(self: string, other: anytype) bool { return std.ascii.eqlIgnoreCase(self, other); } @@ -141,7 +141,7 @@ pub fn eqlComptime(self: string, comptime alt: anytype) bool { @compileError("Invalid size passed to eqlComptime"); }, 2 => { - const check = std.mem.readIntNative(u16, alt[0..alt.len]); + const check = comptime std.mem.readIntNative(u16, alt[0..alt.len]); return self.len == alt.len and std.mem.readIntNative(u16, self[0..2]) == check; }, 1, 3 => { @@ -155,7 +155,7 @@ pub fn eqlComptime(self: string, comptime alt: anytype) bool { return true; }, 4 => { - const check = std.mem.readIntNative(u32, alt[0..alt.len]); + const check = comptime std.mem.readIntNative(u32, alt[0..alt.len]); return self.len == alt.len and std.mem.readIntNative(u32, self[0..4]) == check; }, 6 => { @@ -217,12 +217,12 @@ pub fn eqlComptime(self: string, comptime alt: anytype) bool { return (self.len == alt.len) and first == std.mem.readIntNative(u64, self[0..8]) and second == std.mem.readIntNative(u64, self[8..16]); }, else => { - @compileError(alt ++ " is too long."); + @compileError(alt ++ " is too long."); }, } } -pub fn append(allocator: *std.mem.Allocator, self: string, other: string) !string { +pub inline fn append(allocator: *std.mem.Allocator, self: string, other: string) !string { return std.fmt.allocPrint(allocator, "{s}{s}", .{ self, other }); } |