diff options
author | 2021-09-07 22:08:18 -0700 | |
---|---|---|
committer | 2021-09-07 22:08:18 -0700 | |
commit | 2a6edf00cdb1326267d9099adc2986c94f048134 (patch) | |
tree | 827830dd77e1feb5fe5b292b2a1f755442bdd400 /examples | |
parent | cbd2c56a1fb0fd36f34af20a38e681d6e5e9d64b (diff) | |
download | bun-2a6edf00cdb1326267d9099adc2986c94f048134.tar.gz bun-2a6edf00cdb1326267d9099adc2986c94f048134.tar.zst bun-2a6edf00cdb1326267d9099adc2986c94f048134.zip |
lotta changes
Diffstat (limited to 'examples')
25 files changed, 2669 insertions, 660 deletions
diff --git a/examples/hello-next/bun-framework-next/.npmignore b/examples/hello-next/bun-framework-next/.npmignore new file mode 100644 index 000000000..dc0954477 --- /dev/null +++ b/examples/hello-next/bun-framework-next/.npmignore @@ -0,0 +1,2 @@ +*.bun +node_modules
\ No newline at end of file diff --git a/examples/hello-next/bun-framework-next/bun-error.css b/examples/hello-next/bun-framework-next/bun-error.css new file mode 100644 index 000000000..64801411f --- /dev/null +++ b/examples/hello-next/bun-framework-next/bun-error.css @@ -0,0 +1,288 @@ +:host { + --bun-error-color: #e33737; + --bun-error-monospace: ui-monospace, Menlo, Monaco, "Cascadia Mono", + "Segoe UI Mono", "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", + "Source Code Pro", "Fira Mono", "Droid Sans Mono", "Courier New", monospace; +} + +a { + color: inherit; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} +#BunErrorOverlay-container { + box-shadow: 0px 16px 24px rgba(0, 0, 0, 0.06), 0px 2px 6px rgba(0, 0, 0, 0.1), + 0px 0px 1px rgba(0, 0, 0, 0.04); + backdrop-filter: blur(42px); + backface-visibility: visible; + border: inset 1px solid rgba(0, 0, 0, 0.2); + border-radius: 17px; + background-color: rgba(255, 255, 255, 0.92); + width: 480px; + + position: fixed; + top: 120px; + right: 48px; + z-index: 999999; + + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, + Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; +} + +#BunErrorOverlay-container a { + color: inherit; +} + +.BunError-Summary-ErrorIcon { + content: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAgCAYAAAB3j6rJAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJiSURBVHgBzZdLUttAEIa7RwpVeKUD4Ip8hFSB7V3kG8AJgBPgG+CcAG4QcwPfIFpiigU5gRWcqmy1AVwVaTo9Y+yyiEeakc3jX7j0GEmfe7r/6QH4IELYUJNuN/LyPMwRU2g04lYcp1BDtUEYIPSJvvNhtHI5QcTB3vX1FThKQE0xxI8XEEohEQ2n+/sROKoWyP3BwYn6qHGA553DW4CgEFUfin6328fwmiDTbldBhFXjiHNlEkUBWMoJRCUoSNm3HB6Kx0fbsW4gnpQDQLT/l4hntlGxBlHR4NJ0mndW4D08WCWuNYgv5YXhVsJmNASi0bqbnNj9P2pKtwGiyxXxcM2tJNvd/bI3Hp82b26OJOK3dc9nc+PbHMRUrhyJgqV7QowMr4iqTK4SpNK8VvRXSnNiVphcKYhO0BLzIkvAZ5WaXCmID6AeDGFLYpO7NJWzEUSbF9EAHKTagYohgcnkjCDavKoVgqNMJrcWpKZ5AQlh46LBp6enCysQ36LuFy8tnBFZ2Tkn+cnLcv6vQ1PlypViC6I+PsiEUB3ZomMLLZ+Mm+Nxzwgy7XQmsMVKKVWe95q3t7E6LEyNi3ktRZSWrTWl8rxl5JcgVeZlUJI1Gq3FWsM+cQpuCn91Ov0CiEd0Bo7RkERXq2tNPps5R4UBzlU5axAdDQDrbmr5EsSvhQs7OxG4S5ucTtb7dntYxzeeNWLzi3MhWpwnxy4d3IpSX/0yxGeor0OGmPcqWHu/FixypNY2cZvSINxZ/YT3VTIHmc0u1Qm8k9R+WYO07u7SDLHH+1bnzfNGYjPkhfJIbdr/AfAS02LsKGiuAAAAAElFTkSuQmCC"); + width: 20px; + height: 19px; + + margin-right: 6px; + display: block; +} + +.BunError-Summary-CloseIcon { + content: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAKKSURBVHgBxZjpTsMwEISnaTmLKLf4AX94/7fiFlRcJaUKl6exK8e1k7XTY6QVUbDjj/V4bdNBe2Uquio2nPdfKn6RqA7StKuir2JHxXZNO4LlKkb65zeWBLavYxdpelMxhABQCkaQI6QDuRrqCEoCdqjiFItXoeIagex1Gzqfo8zUMsSxByo+Vfz4fokaqH0sVx09xhxcCOwY5RSuQgbuHVZ58YGx0RlWK8LtoYT74wsXjEXyHM3eW4Y4JgFZ76ZV2xancAPrE+3T44MNRiCp2bnd5MK29A0rfyFsP7VRz3pxLOxoF8ctFZeYz7wRPfOgn/mHX6B5Rui1zP7gDmQaWc8TlEXytwGKKpy+dRoYMG41Um+52fHBuVBG0jH6ZpAtyMVV20MYLgRFq+xBpm1TFrjtbAo7dfUAI1SzxMr9ocF8UFIPUx2TsQxx4pTQ9G7migVAVYBiwagQnK0kKBsotdITblDz7eRDgAH7QZrop9CBj/67gbywVmTAxGdxVKEeGtoQKgkusz4QoxDUbK+zZOCibkzGW/yYtMawTNx73tPkJ/CXEj7zMEjPSY7zRWYNJtUwAGVWX2i1sgi/QabcgJn7X4p8JSEEJ139467TqS/oxAvup34+QrhOmR1ijHLV89uS2xY9+WjPN7N3hbRiu0hNj1U2BKfzGesVs/XCBzc7r0j32iLEbE1Xs2/aHtHivzQtxEzNTia+VUIoGnaA1Yl3iEptDC1fblGcb2nRbSNC3cGZpbq6MtGdCJf6f7Qm0c+38BwiJANKbzexeoJegT7FZOIA5SbdFjDXUJO6RrFTRChe82Jv7PQPbcFyMJZ0aOMd3qx47SMoyw5B6VnjF2aECyjXMFEl6B+GYop4atKAigAAAABJRU5ErkJggg=="); + width: 22px; + height: 22px; + border-radius: 50%; + cursor: pointer; +} + +.BunError-Summary-CloseIcon:hover { + transform: scale(1.2); + + background-color: rgb(255, 255, 255); +} + +.BunError-Summary { + display: grid; + grid-template-columns: min-content auto min-content; + grid-template-rows: 46px; + align-items: center; + padding: 0 18px; + border-bottom: 1px solid rgb(220, 220, 220); +} + +.BunError-footer { + display: grid; + padding: 12px 18px; + justify-content: flex-end; + border-top: 1px solid rgb(220, 220, 220); + align-items: center; +} + +.BunError-Summary-Title { + font-weight: 500; + letter-spacing: 0.36px; +} + +.BunError-ErrorTag, +.BunError-error-code { + color: rgb(165, 165, 165); + font-weight: 500; + font-size: 12pt; +} + +.BunError-ErrorTag { + font-size: 14px; + text-transform: uppercase; + font-weight: 300; +} + +.BunError-error-header { + display: flex; + align-items: center; + gap: 0.5ch; +} + +.BunError-error-message { + color: var(--bun-error-color); + font-size: 16pt; + font-weight: bold; +} + +.BunError-list { + margin-top: 14px; + gap: 14px; +} + +.BunError-error-subtitle, +.BunError-error-header, +.BunError-error-message { + padding-left: 18px; + padding-right: 18px; +} + +.BunError-error-subtitle { + font-size: 500; +} + +.BunError-NativeStackTrace { + margin-top: 0; +} + +.BunError-NativeStackTrace-filename { + padding: 8px 18px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + font-weight: 500; + letter-spacing: 0.36px; + margin-bottom: 8px; + display: block; +} + +.BunError-NativeStackTrace-filename:hover { + text-decoration: underline; +} + +.BunError-SourceLines-lines { +} + +.BunError-SourceLines { + display: grid; + grid-template-columns: min-content auto; + grid-template-rows: repeat(16px, 6); + column-gap: 13px; + font-size: 14px; + padding-left: 24px; + align-items: center; + position: relative; + overflow-x: auto; +} + +.BunError-SourceLine-text { + white-space: pre; + display: block; + + font-family: var(--bun-error-monospace); +} + +.BunError-SourceLine-number { + font-variant: tabular-nums; + text-align: right; + user-select: none; + -webkit-user-select: none; +} + +.BunError-SourceLine-number--empty { + color: rgb(165, 165, 165); +} + +.BunError-SourceLine-number, +.BunError-SourceLine-text { + height: 18px; +} + +.BunError-SourceLines-highlighter--0, +.BunError-SourceLines-highlighter--1, +.BunError-SourceLines-highlighter--2, +.BunError-SourceLines-highlighter--3, +.BunError-SourceLines-highlighter--4, +.BunError-SourceLines-highlighter--5 { + position: absolute; +} + +.BunError-SourceLine-text--highlight { + color: #e33737; +} + +#BunError-poweredBy { + height: 16px; + + content: url("data:image/webp;base64,UklGRhwFAABXRUJQVlA4TBAFAAAv3MAHEBeioG0jx3f8MY+fGAgkbdz7Zz4Ekjbu/TMftpEkOaFfC5vgSJ4sHswjm7TZk7R34AJUQAFAQwYAQAUkQAZUAFTUz5XDIaPd77AAN2DlBrAAG/Ai8CFwcKICP6L+BzgTEBEBp6xqWyZJejDAWERMQEwHEuEip1yEmPDc/w1qRs7/OqL/EyBbtu22bQ4ViCHTKM0gUUNmIjMmZfu6s7nz3v//KwIgRfe3iP5PAP9bdVNLfR/hfdqK3bxLjDgr9Q4JGpfk7xHxPPu8KRdApEaiIpdSr8iU9id7Cn+vE6WbWqRuTORqm7pujCV+LKW8jyymEZHGALqpRer76LU4NXya9fhb5XgQZ2ks02uxtgBmtXSrBEAr1jO04mxfiazx06Lp71TgQXzbzoPYWSMoxV4pGLEWaMXz/xuHIyPevACm4r6BEXcaNBZeGPGt1NvmKij9pFL47cE48TgLaksRlF6SgnhtsKbrV/w0rVdO2yhdg+lKg+naB9OvK/+Ko+2KrNfeTfuV0/pp2q5rj3/G9OtK22C7ou3Laj6EXEvfHMYnOvM4D8R+Lf434PQ9/din0Vrt6wYsundZj+7QABzNPoeumpMa4Gj2JQ7mqlq3735vqjUCWmxzoq9D9C/217cCWbOtVPXsNvXOt7pD0NxVLV2xAklbflW9A6BF/YFD/clVawBi1XYX3+WbrHdRa4SiE8uWaDJcXbo4GhmrzhM41BWo+jtw6DtAsQJRfQegmSFqjcCpaeC9ALFaI5A0AVnvCWL1G2uEeOsJSXUnJFpjuI1xyWZsUVfok56wa6ZPesChEXZLc4VFN8ga6Zt1FAF23emL70DQGgGW7yJAbL4DQbedOdGvceRjyE2vbRD0hpfOg6h/wKw7vDyyJxwa4PZmmDV2hb74Zph0ZtHM8P6mMMw6Q5EmAA4pwzhOxrDpNw9oVijKWCtQzVCddwsUC6DWYfvi1jpsurLrMcrfnKOkOyySBkKi9UjOnkUcVd9QvzqtzFaCBprH6HPlSfVhjd3+J6VnNNoCmih8weaRVigaPhVg0XiYobgvOgPNm8dPKk93PUavb/KDDUhEExzSFiPJ/e7GcgwWLXDqOlg0A6G5FzdInocV4Pb9YYuPXhpGa4RZy6h+8x4VnYGZSIdE87GkPnJbj6WG7qU7LFoGWTeAYtYAi7WYu6THIHk/OjQNkm+g6dolv/HoVq30W9pqosleymsXay/vPVnXuL60RqDoayaeWukPtQA0detC831MxFPzo1A1RaZTbyBp3eeYbF+Z5pia7gNNlNEae/EtMHsOp+MNIFbHNQ6imrqsho7f/FjjI+bquEaA4rDmb87q8IfhZEdEP8ZyimkfHkXcq/qzMIy5qe2aGBdb7BY9GcfStTQBFM8RMXftFRmmpv7Ewxo+heYWs9oSH5dEGQa6mPXhCEHjdzkbZOGjBjAvkafzMk88XCaGcebhtCwzH2eeLss88XCeJ2CZeBhnYFrmic+a6M8AdaeaNj2OAeRenPy1HQeNi/U3jwIf/sszorAfTjqSf6u8rgBgWnrwcVBaOELuKhA0ruzVW7d/RGsMGJedKklKF5+rDuLSwad4ki4fA8G1jRdAUtkKZQn/Xb8pURYOgbhgEb5BfMYsIlwdwBmfMYtwdYBpwSLCxwCgzpiFCw0AScEsfB4BxHLw3x1vs1WIgXWaagBQOs1NAu94kadaAUCS5hsFe7wwCZx6sVF4/wI="); +} + +#BunError-SourceLine-text-highlightExpression { + font-weight: bold; + text-decoration-style: wavy; +} + +.BunError-JSException--TypeError #BunError-SourceLine-text-highlightExpression { + border: 1px solid rgba(0, 0, 0, 0.2); +} +.BunError-Indented { + display: inline-block; + user-select: none; + -webkit-user-select: none; +} + +.BunError-divet { + vertical-align: bottom; + user-select: none; + -webkit-user-select: none; +} + +.BunError-error-typename { + font-family: var(--bun-error-monospace); + color: #e39437; + font-weight: bold; +} + +.BunError-error-muted { + font-weight: normal; + user-select: none; + -webkit-user-select: none; +} + +.BunError-error-muted, +.BunError-StackFrame--muted { + color: rgb(165, 165, 165); +} + +.BunError-NativeStackTrace .BunError-error-typename { + user-select: none; + -webkit-user-select: none; +} + +.BunError-StackFrame-link { +} + +.BunError-StackFrame-link-content { + display: flex; + gap: 0.25ch; + white-space: nowrap; +} + +.BunError-StackFrame { + display: table-row; +} + +.BunError-StackFrame-identifier { + padding-right: 18px; + font-size: 0.8em; + font-family: var(--bun-error-monospace); + letter-spacing: 0.49px; +} + +.BunError-error-message--mono { + font-family: var(--bun-error-monospace); +} +.BunError-StackFrame-identifier, +.BunError-StackFrame-link { + display: table-cell; + font-weight: 500; +} + +.BunError-BuildError { + padding-bottom: 18px; +} + +.BunError-StackFrame-link-content { + font-size: 0.8em; +} + +.BunError-StackFrames { + display: table; + table-layout: auto; + padding: 13px 10px; + margin: 8px auto; + border-radius: 4px; + + background-color: rgb(244, 244, 244); +} diff --git a/examples/hello-next/bun-framework-next/bun-error.tsx b/examples/hello-next/bun-framework-next/bun-error.tsx new file mode 100644 index 000000000..5702f66e6 --- /dev/null +++ b/examples/hello-next/bun-framework-next/bun-error.tsx @@ -0,0 +1,783 @@ +import type { + FallbackMessageContainer, + JSException as JSExceptionType, + Message, + SourceLine, + StackFrame, + Problems, + FallbackStep, + StackTrace, + Location, + JSException, + WebsocketMessageBuildFailure, +} from "../../../src/api/schema"; + +import ReactDOM from "react-dom"; +import { + useCallback, + useState, + useEffect, + useLayoutEffect, + createContext, + useContext, + Children, +} from "react"; + +enum StackFrameScope { + Eval = 1, + Module = 2, + Function = 3, + Global = 4, + Wasm = 5, + Constructor = 6, +} + +enum JSErrorCode { + Error = 0, + EvalError = 1, + RangeError = 2, + ReferenceError = 3, + SyntaxError = 4, + TypeError = 5, + URIError = 6, + AggregateError = 7, + + // StackOverflow & OutOfMemoryError is not an ErrorType in <JavaScriptCore/ErrorType.h> within JSC, so the number here is just totally made up + OutOfMemoryError = 8, + BundlerError = 252, + StackOverflow = 253, + UserErrorCode = 254, +} + +const JSErrorCodeLabel = { + 0: "Error", + 1: "EvalError", + 2: "RangeError", + 3: "ReferenceError", + 4: "SyntaxError", + 5: "TypeError", + 6: "URIError", + 7: "AggregateError", + 253: "StackOverflow", + 8: "OutOfMemory", +}; + +const BUN_ERROR_CONTAINER_ID = "__bun-error__"; + +enum RuntimeType { + Nothing = 0x0, + Function = 0x1, + Undefined = 0x2, + Null = 0x4, + Boolean = 0x8, + AnyInt = 0x10, + Number = 0x20, + String = 0x40, + Object = 0x80, + Symbol = 0x100, + BigInt = 0x200, +} + +enum ErrorTagType { + build, + resolve, + server, + client, + hmr, +} + +const ErrorTag = ({ type }: { type: ErrorTagType }) => ( + <div className={`BunError-ErrorTag BunError-ErrorTag--${ErrorTagType[type]}`}> + {ErrorTagType[type]} + </div> +); + +const errorTags = [ + <ErrorTag type={ErrorTagType.build}></ErrorTag>, + <ErrorTag type={ErrorTagType.resolve}></ErrorTag>, + <ErrorTag type={ErrorTagType.server}></ErrorTag>, + <ErrorTag type={ErrorTagType.client}></ErrorTag>, + <ErrorTag type={ErrorTagType.hmr}></ErrorTag>, +]; + +const normalizedFilename = (filename: string, cwd: string): string => { + if (filename.startsWith(cwd)) { + return filename.substring(cwd.length); + } + + return filename; +}; + +const blobFileURL = (filename: string): string => { + return new URL("/blob:" + filename, location.href).href; +}; + +const srcFileURL = (filename: string, line: number, column: number): string => { + if (filename.endsWith(".bun")) { + return new URL("/" + filename, location.href).href; + } + + var base = `/src:${filename}`; + if (line > -1) { + base = base + `:${line}`; + + if (column > -1) { + base = base + `:${column}`; + } + } + + return new URL(base, location.href).href; +}; + +class FancyTypeError { + constructor(exception: JSException) { + this.runtimeType = exception.runtime_type || 0; + this.runtimeTypeName = RuntimeType[this.runtimeType] || "undefined"; + this.message = exception.message; + this.explain = ""; + + this.normalize(exception); + } + + runtimeType: RuntimeType; + explain: string; + runtimeTypeName: string; + message: string; + + normalize(exception: JSException) { + let i = exception.message.lastIndexOf(" is "); + if (i === -1) return; + const partial = exception.message.substring(i + " is ".length); + const nextWord = /(["a-zA-Z0-9_\.]+)\)$/.exec(partial); + if (nextWord && nextWord[0]) { + this.runtimeTypeName = nextWord[0]; + this.runtimeTypeName = this.runtimeTypeName.substring( + 0, + this.runtimeTypeName.length - 1 + ); + switch (this.runtimeTypeName.toLowerCase()) { + case "undefined": { + this.runtimeType = RuntimeType.Undefined; + break; + } + case "null": { + this.runtimeType = RuntimeType.Null; + break; + } + case "string": { + this.runtimeType = RuntimeType.String; + break; + } + case "true": + case "false": { + this.runtimeType = RuntimeType.Boolean; + break; + } + + case "number": + this.runtimeType = RuntimeType.Number; + break; + + case "bigint": + this.runtimeType = RuntimeType.BigInt; + break; + + case "symbol": + this.runtimeType = RuntimeType.Symbol; + break; + default: { + this.runtimeType = RuntimeType.Object; + break; + } + } + this.message = exception.message.substring(0, i); + this.message = this.message.substring( + 0, + this.message.lastIndexOf("(In ") + ); + } + } +} + +var onClose = dismissError; + +const IndentationContext = createContext(0); +const SourceLines = ({ + sourceLines, + highlight = -1, + highlightColumnStart = 0, + highlightColumnEnd = Infinity, + children, +}: { + sourceLines: SourceLine[]; + highlightColumnStart: number; + highlightColumnEnd: number; + highlight: number; +}) => { + let start = sourceLines.length; + let end = 0; + let dedent = Infinity; + let originalLines = new Array(sourceLines.length); + let _i = 0; + for (let i = 0; i < sourceLines.length; i++) { + // bun only prints \n, no \r\n, so this should work fine + sourceLines[i].text = sourceLines[i].text.replaceAll("\n", ""); + + // This will now only trim spaces (and vertical tab character which never prints) + const left = sourceLines[i].text.trimLeft(); + + if (left.length > 0) { + start = Math.min(start, i); + end = Math.max(end, i + 1); + + dedent = Math.min(sourceLines[i].text.length - left.length, dedent); + } + } + + const _sourceLines = sourceLines.slice(start, end); + const childrenArray = children || []; + const numbers = new Array(_sourceLines.length + childrenArray.length); + const lines = new Array(_sourceLines.length + childrenArray.length); + + let highlightI = 0; + for (let i = 0; i < _sourceLines.length; i++) { + const { line, text } = _sourceLines[i]; + const classes = { + empty: text.trim().length === 0, + highlight: highlight + 1 === line || _sourceLines.length === 1, + }; + if (classes.highlight) highlightI = i; + const _text = classes.empty ? "" : text.substring(dedent); + lines[i] = ( + <div + key={i} + className={`BunError-SourceLine-text ${ + classes.empty ? "BunError-SourceLine-text--empty" : "" + } ${classes.highlight ? "BunError-SourceLine-text--highlight" : ""}`} + > + {classes.highlight ? ( + <> + {_text.substring(0, highlightColumnStart - dedent)} + <span id="BunError-SourceLine-text-highlightExpression"> + {_text.substring( + highlightColumnStart - dedent, + highlightColumnEnd - dedent + )} + </span> + {_text.substring(highlightColumnEnd - dedent)} + </> + ) : ( + _text + )} + </div> + ); + numbers[i] = ( + <div + key={line} + className={`BunError-SourceLine-number ${ + classes.empty ? "BunError-SourceLine-number--empty" : "" + } ${classes.highlight ? "BunError-SourceLine-number--highlight" : ""}`} + > + {line} + </div> + ); + + if (classes.highlight && children) { + i++; + + numbers.push( + ...childrenArray.map((child, index) => ( + <div + key={"highlight-number-" + index} + className={`BunError-SourceLine-number ${ + classes.empty ? "BunError-SourceLine-number--empty" : "" + } ${ + classes.highlight ? "BunError-SourceLine-number--highlight" : "" + }`} + ></div> + )) + ); + lines.push( + ...childrenArray.map((child, index) => ( + <div + key={"highlight-line-" + index} + className={`BunError-SourceLine-text`} + > + {childrenArray[index]} + </div> + )) + ); + } + } + + return ( + <IndentationContext.Provider value={dedent}> + <div className="BunError-SourceLines"> + <div + className={`BunError-SourceLines-highlighter--${highlightI}`} + ></div> + + <div className="BunError-SourceLines-numbers">{numbers}</div> + <div className="BunError-SourceLines-lines">{lines}</div> + </div> + </IndentationContext.Provider> + ); +}; + +const BuildErrorSourceLines = ({ location }: { location: Location }) => { + const { line, line_text, column, file } = location; + const sourceLines: SourceLine[] = [{ line, text: line_text }]; + return ( + <SourceLines + sourceLines={sourceLines} + highlight={line} + highlightColumnStart={column} + highlightColumnEnd={column} + /> + ); +}; + +const BuildErrorStackTrace = ({ location }: { location: Location }) => { + const { cwd } = useContext(ErrorGroupContext); + const filename = normalizedFilename(location.file, cwd); + const { line, column } = location; + return ( + <div className={`BunError-NativeStackTrace`}> + <a + href={srcFileURL(filename, line, column)} + target="_blank" + className="BunError-NativeStackTrace-filename" + > + {filename}:{line}:{column} + </a> + <BuildErrorSourceLines location={location} /> + </div> + ); +}; + +const StackFrameIdentifier = ({ + functionName, + scope, +}: { + functionName?: string; + scope: StackFrameScope; +}) => { + switch (scope) { + case StackFrameScope.Constructor: { + return functionName ? `new ${functionName}` : "new (anonymous)"; + break; + } + + case StackFrameScope.Eval: { + return "eval"; + break; + } + + case StackFrameScope.Module: { + return "(esm)"; + break; + } + + case StackFrameScope.Global: { + return "(global)"; + break; + } + + case StackFrameScope.Wasm: { + return "(wasm)"; + break; + } + + default: { + return functionName ? functionName : "λ()"; + break; + } + } +}; + +const NativeStackFrame = ({ + frame, + isTop, +}: { + frame: StackFrame; + isTop: boolean; +}) => { + const { cwd } = useContext(ErrorGroupContext); + const { + file, + function_name: functionName, + position: { line, column_start: column }, + scope, + } = frame; + const fileName = normalizedFilename(file, cwd); + return ( + <div + className={`BunError-StackFrame ${ + fileName.endsWith(".bun") ? "BunError-StackFrame--muted" : "" + }`} + > + <div + title={StackFrameScope[scope]} + className="BunError-StackFrame-identifier" + > + <StackFrameIdentifier functionName={functionName} scope={scope} /> + </div> + + <a + target="_blank" + href={blobFileURL(fileName)} + className="BunError-StackFrame-link" + > + <div className="BunError-StackFrame-link-content"> + <div className={`BunError-StackFrame-file`}>{fileName}</div> + {line > -1 && ( + <div className="BunError-StackFrame-line">:{line + 1}</div> + )} + {column > -1 && ( + <div className="BunError-StackFrame-column">:{column}</div> + )} + </div> + </a> + </div> + ); +}; + +const NativeStackFrames = ({ frames }) => { + const items = new Array(frames.length); + for (let i = 0; i < frames.length; i++) { + items[i] = <NativeStackFrame key={i} frame={frames[i]} />; + } + + return <div className="BunError-StackFrames">{items}</div>; +}; + +const NativeStackTrace = ({ + frames, + sourceLines, + children, +}: { + frames: StackFrame[]; + sourceLines: SourceLine[]; +}) => { + const { file = "", position } = frames[0]; + const { cwd } = useContext(ErrorGroupContext); + const filename = normalizedFilename(file, cwd); + return ( + <div className={`BunError-NativeStackTrace`}> + <a + href={blobFileURL(filename)} + target="_blank" + className="BunError-NativeStackTrace-filename" + > + {filename}:{position.line + 1}:{position.column_start} + </a> + {sourceLines.length > 0 && ( + <SourceLines + highlight={position.line} + sourceLines={sourceLines} + highlightColumnStart={position.column_start} + highlightColumnEnd={position.column_stop} + > + {children} + </SourceLines> + )} + {frames.length > 0 && <NativeStackFrames frames={frames} />} + </div> + ); +}; + +const divet = <span className="BunError-divet">^</span>; +const DivetRange = ({ start, stop }) => { + const length = Math.max(stop - start, 0); + if (length === 0) return null; + return ( + <span + className="BunError-DivetRange" + style={{ width: `${length - 1}ch` }} + ></span> + ); +}; + +const Indent = ({ by, children }) => { + const amount = useContext(IndentationContext); + return ( + <> + {` `.repeat(by - amount)} + {children} + </> + ); +}; + +const JSException = ({ value }: { value: JSExceptionType }) => { + switch (value.code) { + case JSErrorCode.TypeError: { + const fancyTypeError = new FancyTypeError(value); + + if (fancyTypeError.runtimeType !== RuntimeType.Nothing) { + return ( + <div + className={`BunError-JSException BunError-JSException--TypeError`} + > + <div className="BunError-error-header"> + <div className={`BunError-error-code`}>TypeError</div> + {errorTags[ErrorTagType.server]} + </div> + + <div className={`BunError-error-message`}> + {fancyTypeError.message} + </div> + + {fancyTypeError.runtimeTypeName.length && ( + <div className={`BunError-error-subtitle`}> + It's{" "} + <span className="BunError-error-typename"> + {fancyTypeError.runtimeTypeName} + </span> + . + </div> + )} + + {value.stack && ( + <NativeStackTrace + frames={value.stack.frames} + sourceLines={value.stack.source_lines} + > + <Indent by={value.stack.frames[0].position.column_start}> + <span className="BunError-error-typename"> + {fancyTypeError.runtimeTypeName} + </span> + </Indent> + </NativeStackTrace> + )} + </div> + ); + } + } + + default: { + return ( + <div className={`BunError-JSException`}> + <div className="BunError-error-header"> + <div className={`BunError-error-code`}>{value.name}</div> + {errorTags[ErrorTagType.server]} + </div> + + <div className={`BunError-error-message`}>{value.message}</div> + + {value.stack && ( + <NativeStackTrace + frames={value.stack.frames} + sourceLines={value.stack.source_lines} + /> + )} + </div> + ); + } + } +}; + +const Summary = ({ + errorCount, + onClose, +}: { + errorCount: number; + onClose: Function; +}) => { + return ( + <div className="BunError-Summary"> + <div className="BunError-Summary-ErrorIcon"></div> + <div className="BunError-Summary-Title"> + {errorCount} error{errorCount > 1 ? "s" : ""} on this page + </div> + + <div onClick={onClose} className="BunError-Summary-CloseButton"> + <div className="BunError-Summary-CloseIcon"></div> + </div> + </div> + ); +}; + +const BuildError = ({ message }: { message: Message }) => { + let title = (message.data.text || "").trim(); + const newline = title.indexOf("\n"); + let subtitle = ""; + if (newline > -1) { + subtitle = title.slice(newline + 1).trim(); + title = title.slice(0, newline); + } + return ( + <div className={`BunError-BuildError BunError-BuildError--build`}> + <div className="BunError-error-header"> + <div className={`BunError-error-code`}>BuildError</div> + </div> + + <div className={`BunError-error-message`}>{title}</div> + + {subtitle.length > 0 && ( + <div className={`BunError-error-subtitle`}>{subtitle}</div> + )} + + {message.data.location && ( + <BuildErrorStackTrace location={message.data.location} /> + )} + </div> + ); +}; + +const ResolveError = ({ message }: { message: Message }) => { + const { cwd } = useContext(ErrorGroupContext); + let title = (message.data.text || "").trim(); + const newline = title.indexOf("\n"); + let subtitle = null; + if (newline > -1) { + subtitle = title.slice(newline + 1).trim(); + title = title.slice(0, newline); + } + + return ( + <div className={`BunError-BuildError BunError-BuildError--resolve`}> + <div className="BunError-error-header"> + <div className={`BunError-error-code`}>ResolveError</div> + </div> + + <div className={`BunError-error-message`}> + Can't import{" "} + <span className="BunError-error-message--mono"> + {message.on.resolve} + </span> + </div> + + {subtitle && <div className={`BunError-error-subtitle`}>{subtitle}</div>} + + {message.data.location && ( + <BuildErrorStackTrace location={message.data.location} /> + )} + </div> + ); +}; +const OverlayMessageContainer = ({ + problems, + reason, + router, +}: FallbackMessageContainer) => { + return ( + <div id="BunErrorOverlay-container"> + <div className="BunError-content"> + <div className="BunError-header"> + <Summary + errorCount={problems.exceptions.length + problems.build.errors} + onClose={onClose} + problems={problems} + reason={reason} + /> + </div> + <div className={`BunError-list`}> + {problems.exceptions.map((problem, index) => ( + <JSException key={index} value={problem} /> + ))} + {problems.build.msgs.map((buildMessage, index) => { + if (buildMessage.on.build) { + return <BuildError key={index} message={buildMessage} />; + } else if (buildMessage.on.resolve) { + return <ResolveError key={index} message={buildMessage} />; + } else { + throw new Error("Unknown build message type"); + } + })} + </div> + <div className="BunError-footer"> + <div id="BunError-poweredBy"></div> + </div> + </div> + </div> + ); +}; + +const BuildFailureMessageContainer = ({ + messages, +}: { + messages: Message[]; +}) => { + return ( + <div id="BunErrorOverlay-container"> + <div className="BunError-content"> + <div className="BunError-header"> + <Summary onClose={onClose} errorCount={messages.length} /> + </div> + <div className={`BunError-list`}> + {messages.map((buildMessage, index) => { + if (buildMessage.on.build) { + return <BuildError key={index} message={buildMessage} />; + } else if (buildMessage.on.resolve) { + return <ResolveError key={index} message={buildMessage} />; + } else { + throw new Error("Unknown build message type"); + } + })} + </div> + <div className="BunError-footer"> + <div id="BunError-poweredBy"></div> + </div> + </div> + </div> + ); +}; + +const ErrorGroupContext = createContext<{ cwd: string }>(null); +var reactRoot; + +function renderWithFunc(func) { + if (!reactRoot) { + const root = document.createElement("div"); + root.id = "__bun__error-root"; + + reactRoot = document.createElement("div"); + reactRoot.id = BUN_ERROR_CONTAINER_ID; + reactRoot.style.visibility = "hidden"; + const link = document.createElement("link"); + link.rel = "stylesheet"; + link.href = new URL("/bun:erro.css", document.baseURI).href; + link.onload = () => { + reactRoot.style.visibility = "visible"; + }; + + const shadowRoot = root.attachShadow({ mode: "open" }); + shadowRoot.appendChild(link); + shadowRoot.appendChild(reactRoot); + + document.body.appendChild(root); + ReactDOM.render(func(), reactRoot); + + debugger; + } else { + ReactDOM.render(func(), reactRoot); + } +} + +export function renderFallbackError(fallback: FallbackMessageContainer) { + return renderWithFunc(() => ( + <ErrorGroupContext.Provider value={fallback}> + <OverlayMessageContainer {...fallback} /> + </ErrorGroupContext.Provider> + )); +} + +export function dismissError() { + if (reactRoot) { + ReactDOM.unmountComponentAtNode(reactRoot); + const root = document.getElementById("__bun__error-root"); + if (root) root.remove(); + reactRoot = null; + } +} + +globalThis.renderBuildFailure = ( + failure: WebsocketMessageBuildFailure, + cwd: string +) => { + renderWithFunc(() => ( + <ErrorGroupContext.Provider value={{ cwd }}> + <BuildFailureMessageContainer messages={failure.log.msgs} /> + </ErrorGroupContext.Provider> + )); +}; diff --git a/examples/hello-next/bun-framework-next/bun-error/close.png b/examples/hello-next/bun-framework-next/bun-error/close.png Binary files differnew file mode 100644 index 000000000..11e513a1b --- /dev/null +++ b/examples/hello-next/bun-framework-next/bun-error/close.png diff --git a/examples/hello-next/bun-framework-next/bun-error/error.png b/examples/hello-next/bun-framework-next/bun-error/error.png Binary files differnew file mode 100644 index 000000000..c35e01a2b --- /dev/null +++ b/examples/hello-next/bun-framework-next/bun-error/error.png diff --git a/examples/hello-next/bun-framework-next/client.development.tsx b/examples/hello-next/bun-framework-next/client.development.tsx new file mode 100644 index 000000000..0d019e175 --- /dev/null +++ b/examples/hello-next/bun-framework-next/client.development.tsx @@ -0,0 +1,416 @@ +import "./bun-error"; +globalThis.global = globalThis; +globalThis.Bun_disableCSSImports = true; + +import * as React from "react"; +var onlyChildPolyfill = React.Children.only; +React.Children.only = function (children) { + if (children && typeof children === "object" && children.length == 1) { + return onlyChildPolyfill(children[0]); + } + + return onlyChildPolyfill(children); +}; + +import * as ReactDOM from "react-dom"; +import App from "next/app"; +import mitt, { MittEmitter } from "next/dist/shared/lib/mitt"; +import { RouterContext } from "next/dist/shared/lib/router-context"; +import Router, { + AppComponent, + AppProps, + delBasePath, + hasBasePath, + PrivateRouteInfo, +} from "next/dist/shared/lib/router/router"; + +import * as NextRouteLoader from "next/dist/client/route-loader"; +import { isDynamicRoute } from "next/dist/shared/lib/router/utils/is-dynamic"; +import { + urlQueryToSearchParams, + assign, +} from "next/dist/shared/lib/router/utils/querystring"; +import { setConfig } from "next/dist/shared/lib/runtime-config"; +import { + getURL, + loadGetInitialProps, + NEXT_DATA, + ST, +} from "next/dist/shared/lib/utils"; +// import { Portal } from "next/dist/client/portal"; +import initHeadManager from "next/dist/client/head-manager"; +import { HeadManagerContext } from "next/dist/shared/lib/head-manager-context"; +import PageLoader from "./page-loader"; +import measureWebVitals from "next/dist/client/performance-relayer"; +import { RouteAnnouncer } from "next/dist/client/route-announcer"; +import { + createRouter, + makePublicRouterInstance, +} from "next/dist/client/router"; +export const emitter: MittEmitter<string> = mitt(); + +declare global { + interface Window { + /* test fns */ + __NEXT_HYDRATED?: boolean; + __NEXT_HYDRATED_CB?: () => void; + + /* prod */ + __NEXT_PRELOADREADY?: (ids?: (string | number)[]) => void; + __NEXT_DATA__: NEXT_DATA; + __NEXT_P: any[]; + } +} + +function nextDataFromBunData() { + const { + router: { routes, route, params: paramsList }, + problems, + } = globalThis.__BUN_DATA__; + + const paramsMap = new Map(); + for (let i = 0; i < paramsList.keys.length; i++) { + paramsMap.set( + decodeURIComponent(paramsList.keys[i]), + decodeURIComponent(paramsList.values[i]) + ); + } + + const params = {}; + var url = new URL(location.href); + Object.assign(params, Object.fromEntries(url.searchParams.entries())); + Object.assign(params, Object.fromEntries(paramsMap.entries())); + + const pages = routes.reduce((acc, route) => { + var name = route.substring(route.indexOf("_next") + "_next/".length); + + while (name.startsWith("/")) { + name = name.substring(1); + } + + if (name.startsWith("pages")) { + name = name.substring("pages".length); + } + + while (name.startsWith("/")) { + name = name.substring(1); + } + + if (name.endsWith(".jsx")) { + name = name.substring(0, name.length - ".jsx".length); + } + + if (name.endsWith(".tsx")) { + name = name.substring(0, name.length - ".tsx".length); + } + + if (name.endsWith(".ts")) { + name = name.substring(0, name.length - ".ts".length); + } + + if (name.endsWith(".js")) { + name = name.substring(0, name.length - ".js".length); + } + + acc["/" + name] = [route]; + return acc; + }, {}); + + return { + page: routes[route], + buildId: "1234", + assetPrefix: "", + isPreview: false, + locale: null, + locales: [], + isFallback: false, + err: null, + props: {}, + query: params, + pages, + }; +} + +type RenderRouteInfo = PrivateRouteInfo & { + App: AppComponent; + scroll?: { x: number; y: number } | null; +}; +type RenderErrorProps = Omit<RenderRouteInfo, "Component" | "styleSheets">; + +const nextDataTag = document.getElementById("__NEXT_DATA__"); + +const data: typeof window["__NEXT_DATA__"] = nextDataTag + ? JSON.parse(document.getElementById("__NEXT_DATA__")!.textContent!) + : nextDataFromBunData(); +window.__NEXT_DATA__ = data; + +const { + props: hydrateProps, + err: hydrateErr, + page, + query, + buildId, + assetPrefix, + runtimeConfig, + dynamicIds, + isFallback, + locale, + locales, + domainLocales, + isPreview, +} = data; + +const prefix: string = assetPrefix || ""; + +setConfig({ + serverRuntimeConfig: {}, + publicRuntimeConfig: runtimeConfig || {}, +}); + +let asPath: string = getURL(); + +// make sure not to attempt stripping basePath for 404s +if (hasBasePath(asPath)) { + asPath = delBasePath(asPath); +} + +export const pageLoader: PageLoader = new PageLoader( + buildId, + prefix, + data.pages +); + +const headManager: { + mountedInstances: Set<unknown>; + updateHead: (head: JSX.Element[]) => void; +} = initHeadManager(); +const appElement: HTMLElement | null = document.getElementById("__next"); + +let lastRenderReject: (() => void) | null; +let webpackHMR: any; +export let router: Router; +let CachedApp: AppComponent, onPerfEntry: (metric: any) => void; + +export default function boot(EntryPointNamespace, loader) { + _boot(EntryPointNamespace).then(() => {}, false); +} + +class Container extends React.Component<{ + fn: (err: Error, info?: any) => void; +}> { + componentDidCatch(componentErr: Error, info: any) { + this.props.fn(componentErr, info); + } + + componentDidMount() { + this.scrollToHash(); + + // We need to replace the router state if: + // - the page was (auto) exported and has a query string or search (hash) + // - it was auto exported and is a dynamic route (to provide params) + // - if it is a client-side skeleton (fallback render) + if ( + router.isSsr && + // We don't update for 404 requests as this can modify + // the asPath unexpectedly e.g. adding basePath when + // it wasn't originally present + page !== "/404" && + page !== "/_error" && + (isFallback || + (data.nextExport && + (isDynamicRoute(router.pathname) || + location.search || + process.env.__NEXT_HAS_REWRITES)) || + (hydrateProps && + hydrateProps.__N_SSG && + (location.search || process.env.__NEXT_HAS_REWRITES))) + ) { + // update query on mount for exported pages + router.replace( + router.pathname + + "?" + + String( + assign( + urlQueryToSearchParams(router.query), + new URLSearchParams(location.search) + ) + ), + asPath, + { + // @ts-ignore + // WARNING: `_h` is an internal option for handing Next.js + // client-side hydration. Your app should _never_ use this property. + // It may change at any time without notice. + _h: 1, + // Fallback pages must trigger the data fetch, so the transition is + // not shallow. + // Other pages (strictly updating query) happens shallowly, as data + // requirements would already be present. + shallow: !isFallback, + } + ); + } + } + + componentDidUpdate() { + this.scrollToHash(); + } + + scrollToHash() { + let { hash } = location; + hash = hash && hash.substring(1); + if (!hash) return; + + const el: HTMLElement | null = document.getElementById(hash); + if (!el) return; + + // If we call scrollIntoView() in here without a setTimeout + // it won't scroll properly. + setTimeout(() => el.scrollIntoView(), 0); + } + + render() { + return this.props.children; + } +} + +let CachedComponent: React.ComponentType; + +const wrapApp = + (App: AppComponent) => + (wrappedAppProps: Record<string, any>): JSX.Element => { + const appProps: AppProps = { + ...wrappedAppProps, + Component: CachedComponent, + err: hydrateErr, + router, + }; + return ( + <AppContainer> + <App {...appProps} /> + </AppContainer> + ); + }; + +function AppContainer({ + children, +}: React.PropsWithChildren<{}>): React.ReactElement { + return ( + <Container fn={(error) => <div>{JSON.stringify(error)}</div>}> + <RouterContext.Provider value={makePublicRouterInstance(router)}> + <HeadManagerContext.Provider value={headManager}> + {children} + </HeadManagerContext.Provider> + </RouterContext.Provider> + </Container> + ); +} + +export async function _boot(EntryPointNamespace, isError) { + NextRouteLoader.default.getClientBuildManifest = () => Promise.resolve({}); + + const PageComponent = EntryPointNamespace.default; + + const appScripts = globalThis.__NEXT_DATA__.pages["/_app"]; + if (appScripts && appScripts.length > 0) { + let appSrc; + for (let asset of appScripts) { + if (!asset.endsWith(".css")) { + appSrc = asset; + break; + } + } + + if (appSrc) { + const AppModule = await import(appSrc); + console.assert( + AppModule.default, + appSrc + " must have a default export'd React component" + ); + + CachedApp = AppModule.default; + } else { + CachedApp = App; + } + } + + router = createRouter(page, query, asPath, { + initialProps: hydrateProps, + pageLoader, + App: CachedApp, + Component: CachedComponent, + wrapApp, + err: null, + isFallback: Boolean(isFallback), + subscription: async (info, App, scroll) => { + return render( + Object.assign< + {}, + Omit<RenderRouteInfo, "App" | "scroll">, + Pick<RenderRouteInfo, "App" | "scroll"> + >({}, info, { + App, + scroll, + }) + ); + }, + locale, + locales, + defaultLocale: "", + domainLocales, + isPreview, + }); + + globalThis.next.router = router; + + if (isError) { + ReactDOM.render( + <TopLevelRender + App={CachedApp} + Component={PageComponent} + props={{ pageProps: hydrateProps }} + />, + document.querySelector("#__next") + ); + } else { + ReactDOM.hydrate( + <TopLevelRender + App={CachedApp} + Component={PageComponent} + props={{ pageProps: hydrateProps }} + />, + document.querySelector("#__next") + ); + } +} + +function TopLevelRender({ App, Component, props, scroll }) { + return ( + <AppContainer scroll={scroll}> + <App Component={Component} {...props}></App> + </AppContainer> + ); +} + +export function render(props) { + ReactDOM.render( + <TopLevelRender {...props} />, + document.querySelector("#__next") + ); +} + +export function renderError(e) { + ReactDOM.render( + <AppContainer> + <App Component={<div>UH OH!!!!</div>} pageProps={data.props}></App> + </AppContainer>, + document.querySelector("#__next") + ); +} + +globalThis.next = { + version: "11.1.0", + emitter, + render, + renderError, +}; diff --git a/examples/hello-next/bun-framework-next/fallback.development.tsx b/examples/hello-next/bun-framework-next/fallback.development.tsx new file mode 100644 index 000000000..1cd5f847e --- /dev/null +++ b/examples/hello-next/bun-framework-next/fallback.development.tsx @@ -0,0 +1,82 @@ +import { insertStyleSheet } from "./page-loader"; +import type { + FallbackMessageContainer, + FallbackStep, +} from "../../../src/api/schema"; + +var once = false; +function insertGlobalStyleSheet(detail) { + if (!once) { + document.head.insertAdjacentHTML( + "beforeend", + `<meta name="next-head-count" content="${document.head.childElementCount}">` + ); + once = true; + } + pageLoader.cssQueue.push(insertStyleSheet(detail).then(() => {})); +} + +[...globalThis["__BUN"].allImportedStyles].map((detail) => + insertGlobalStyleSheet(detail) +); + +document.addEventListener("onimportcss", insertGlobalStyleSheet, { + passive: true, +}); + +import { renderError, _boot, pageLoader } from "./client.development"; +import { renderFallbackError } from "bun-error"; + +function renderFallback({ + router, + reason, + problems, +}: FallbackMessageContainer) { + const route = router.routes[router.route]; + + if (!document.getElementById("__next")) { + const next = document.createElement("div"); + next.id = "__next"; + document.body.prepend(next); + } + + document.removeEventListener("onimportcss", insertGlobalStyleSheet); + document.addEventListener("onimportcss", pageLoader.onImportCSS, { + passive: true, + }); + + globalThis.__NEXT_DATA__.pages["/_app"] = [ + ...globalThis.__NEXT_DATA__.pages["/_app"], + ...globalThis["__BUN"].allImportedStyles, + ]; + + return import(route) + .then((Namespace) => { + return _boot(Namespace, true); + }) + .then(() => { + const cssQueue = pageLoader.cssQueue.slice(); + pageLoader.cssQueue = []; + return Promise.all([...cssQueue]); + }) + .finally(() => { + document.body.style.visibility = "visible"; + document.removeEventListener("onimportcss", pageLoader.onImportCSS); + }); +} + +export default function render(props: FallbackMessageContainer) { + renderFallback(props).then( + () => { + Promise.all(pageLoader.cssQueue).finally(() => { + renderFallbackError(props); + document.body.style.visibility = "visible"; + }); + }, + (err) => { + Promise.all(pageLoader.cssQueue).finally(() => { + renderFallbackError(props); + }); + } + ); +} diff --git a/examples/hello-next/bun-framework-next/index.js b/examples/hello-next/bun-framework-next/index.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/examples/hello-next/bun-framework-next/index.js diff --git a/examples/hello-next/bun-framework-next/next-server.tsx b/examples/hello-next/bun-framework-next/next-server.tsx new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/examples/hello-next/bun-framework-next/next-server.tsx diff --git a/examples/hello-next/bun-framework-next/package.json b/examples/hello-next/bun-framework-next/package.json new file mode 100644 index 000000000..af6286343 --- /dev/null +++ b/examples/hello-next/bun-framework-next/package.json @@ -0,0 +1,81 @@ +{ + "name": "bun-framework-next", + "version": "0.0.0-18", + "description": "", + "framework": { + "displayName": "Next.js", + "static": "public", + "assetPrefix": "_next/", + "router": { + "dir": [ + "pages", + "src/pages" + ], + "extensions": [ + ".js", + ".ts", + ".tsx", + ".jsx" + ] + }, + "css": "onimportcss", + "development": { + "client": "client.development.tsx", + "fallback": "fallback.development.tsx", + "server": "server.development.tsx", + "css": "onimportcss", + "define": { + "client": { + ".env": "NEXT_PUBLIC_", + "defaults": { + "process.env.__NEXT_TRAILING_SLASH": "false", + "process.env.NODE_ENV": "\"development\"", + "process.env.__NEXT_ROUTER_BASEPATH": "''", + "process.env.__NEXT_SCROLL_RESTORATION": "false", + "process.env.__NEXT_I18N_SUPPORT": "false", + "process.env.__NEXT_HAS_REWRITES": "false", + "process.env.__NEXT_ANALYTICS_ID": "null", + "process.env.__NEXT_OPTIMIZE_CSS": "false", + "process.env.__NEXT_CROSS_ORIGIN": "''", + "process.env.__NEXT_STRICT_MODE": "false", + "process.env.__NEXT_IMAGE_OPTS": "null" + } + }, + "server": { + ".env": "NEXT_", + "defaults": { + "process.env.__NEXT_TRAILING_SLASH": "false", + "process.env.__NEXT_OPTIMIZE_FONTS": "false", + "process.env.NODE_ENV": "\"development\"", + "process.env.__NEXT_OPTIMIZE_IMAGES": "false", + "process.env.__NEXT_OPTIMIZE_CSS": "false", + "process.env.__NEXT_ROUTER_BASEPATH": "''", + "process.env.__NEXT_SCROLL_RESTORATION": "false", + "process.env.__NEXT_I18N_SUPPORT": "false", + "process.env.__NEXT_HAS_REWRITES": "false", + "process.env.__NEXT_ANALYTICS_ID": "null", + "process.env.__NEXT_CROSS_ORIGIN": "''", + "process.env.__NEXT_STRICT_MODE": "false", + "process.env.__NEXT_IMAGE_OPTS": "null", + "global": "globalThis", + "window": "undefined" + } + } + } + }, + "production": { + "client": "client.production.tsx", + "server": "server.production.tsx", + "fallback": "fallback.production.tsx", + "css": "onimportcss" + } + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "react-is": "^17.0.2" + } +} diff --git a/examples/hello-next/bun-framework-next/page-loader.ts b/examples/hello-next/bun-framework-next/page-loader.ts new file mode 100644 index 000000000..fc07578db --- /dev/null +++ b/examples/hello-next/bun-framework-next/page-loader.ts @@ -0,0 +1,147 @@ +import NextPageLoader from "next/dist/client/page-loader"; +import getAssetPathFromRoute from "next/dist/shared/lib/router/utils/get-asset-path-from-route"; +// import createRouteLoader from "./route-loader"; + +export function insertStyleSheet(url: string) { + if (document.querySelector(`link[href="${url}"]`)) { + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + const link = document.createElement("link"); + link.rel = "stylesheet"; + + link.onload = () => resolve(); + link.onerror = () => reject(); + + link.href = url; + + // if (headCount) { + // document.head.insertBefore(headCount, link); + // } else { + document.head.appendChild(link); + // } + }); +} + +export default class PageLoader extends NextPageLoader { + public routeLoader: RouteLoader; + + constructor(_, __, pages) { + super(_, __); + + // TODO: assetPrefix? + // this.routeLoader = {}; //createRouteLoader(""); + + // Rewrite the pages object to omit the entry script + // At this point, the entry point has been loaded so we don't want to do that again. + for (let name in pages) { + for (let i = 0; i < pages[name].length; i += 1) { + const lastDot = pages[name][i].lastIndexOf("."); + if (lastDot == -1) continue; + if ( + pages[name][i].substring(lastDot - ".entry".length, lastDot) !== + ".entry" + ) + continue; + + pages[name][i] = + pages[name][i].substring(0, lastDot - ".entry".length) + + pages[name][i].substring(lastDot); + } + } + + this.pages = pages; + this.pageList = Object.keys(this.pages); + } + + pageList: string[]; + pages: Record<string, string[]>; + + getPageList() { + return this.pageList; + } + + cssQueue = []; + + onImportCSS = (event) => { + this.cssQueue.push( + insertStyleSheet(event.detail).then( + () => {}, + () => {} + ) + ); + }; + + prefetch(route) { + return Promise.resolve({}); + } + + async loadPage(route: string): Promise<GoodPageCache> { + const assets = + this.pages[route] || this.pages[getAssetPathFromRoute(route)]; + + var src; + console.log(getAssetPathFromRoute(route), assets); + for (let asset of assets) { + if (!asset.endsWith(".css")) { + src = asset; + break; + } + } + console.assert(src, "Invalid or unknown route passed to loadPage"); + + document.removeEventListener("onimportcss", this.onImportCSS); + this.cssQueue.length = 0; + document.addEventListener("onimportcss", this.onImportCSS, { + passive: true, + }); + + try { + const res = await import(src); + + if (this.cssQueue.length > 0) { + await Promise.all(this.cssQueue); + this.cssQueue.length = 0; + } + + document.removeEventListener("onimportcss", this.onImportCSS); + + if (this.cssQueue.length > 0) { + await Promise.all(this.cssQueue); + + this.cssQueue.length = 0; + } + + return { + page: res.default, + mod: res, + styleSheets: [], + __N_SSG: false, + __N_SSP: false, + }; + } catch (exception) { + console.error({ exception }); + } + + // return this.routeLoader.loadRoute(route).then((res) => { + // debugger; + // if ("component" in res) { + // return { + // page: res.component, + // mod: res.exports, + // styleSheets: res.styles.map((o) => ({ + // href: o.href, + // text: o.content, + // })), + // }; + // } + // throw res.error; + // }); + } + + // not used in development! + // prefetch(route: string): Promise<void> { + // return this.routeLoader.prefetch(route); + // } +} diff --git a/examples/hello-next/bun-framework-next/render.tsx b/examples/hello-next/bun-framework-next/render.tsx new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/examples/hello-next/bun-framework-next/render.tsx diff --git a/examples/hello-next/bun-framework-next/renderDocument.tsx b/examples/hello-next/bun-framework-next/renderDocument.tsx new file mode 100644 index 000000000..356ff788b --- /dev/null +++ b/examples/hello-next/bun-framework-next/renderDocument.tsx @@ -0,0 +1,722 @@ +import * as App from "next/app"; +import { AmpStateContext } from "next/dist/shared/lib/amp-context"; +import { HeadManagerContext } from "next/dist/shared/lib/head-manager-context"; +import Loadable from "next/dist/shared/lib/loadable"; +import { LoadableContext } from "next/dist/shared/lib/loadable-context"; +import { RouterContext } from "next/dist/shared/lib/router-context"; +import { NextRouter } from "next/dist/shared/lib/router/router"; +import { + AppType, + ComponentsEnhancer, + DocumentInitialProps, + DocumentProps, + DocumentType, + getDisplayName, + loadGetInitialProps, + NextComponentType, + RenderPage, + RenderPageResult, + HtmlContext, +} from "next/dist/shared/lib/utils"; +import * as NextDocument from "next/document"; +import * as ReactDOMServer from "react-dom/server.browser"; +import * as url from "url"; +import * as React from "react"; +import * as ReactIs from "react-is"; +import { BODY_RENDER_TARGET } from "next/constants"; + +const dev = process.env.NODE_ENV === "development"; + +type ParsedUrlQuery = Record<string, string | string[]>; + +const isJSFile = (file: string) => + file.endsWith(".js") || + file.endsWith(".jsx") || + file.endsWith(".mjs") || + file.endsWith(".ts") || + file.endsWith(".tsx"); + +const notImplementedProxy = (base) => + new Proxy( + {}, + { + deleteProperty: function (target, prop) { + return undefined; + }, + enumerate: function (oTarget, sKey) { + return [].entries(); + }, + ownKeys: function (oTarget, sKey) { + return [].values(); + }, + has: function (oTarget, sKey) { + return false; + }, + defineProperty: function (oTarget, sKey, oDesc) { + return undefined; + }, + getOwnPropertyDescriptor: function (oTarget, sKey) { + return undefined; + }, + get(this, prop) { + throw new ReferenceError( + `${base} is not available for this environment.` + ); + }, + set(this, prop, value) { + throw new ReferenceError( + `${base} is not available for this environment.` + ); + }, + } + ); + +globalThis.fetch = (url, options) => { + return Promise.reject(new Error(`fetch is not implemented yet. sorry!!`)); +}; + +function getScripts(files: DocumentFiles) { + const { context, props } = this; + const { + assetPrefix, + buildManifest, + isDevelopment, + devOnlyCacheBusterQueryString, + disableOptimizedLoading, + } = context; + const normalScripts = files.allFiles.filter(isJSFile); + const lowPriorityScripts = buildManifest.lowPriorityFiles?.filter(isJSFile); + + return [...normalScripts, ...lowPriorityScripts].map((file) => { + return ( + <script + key={file} + src={`${encodeURI(file)}${devOnlyCacheBusterQueryString}`} + nonce={props.nonce} + async + crossOrigin={props.crossOrigin || process.env.__NEXT_CROSS_ORIGIN} + type="module" + /> + ); + }); +} + +// function fixLink(from: string) { +// if (from.startsWith("/_next/http://") || from.startsWith("/_next/https://")) +// return from.substring("/_next".length); +// return from; +// } + +// function cloneWithOverwrittenLink(element: React.ReactElement<any>) { +// const props = { ...element.props }; +// if ("href" in element.props) { +// props.href = fixLink(props.href); +// } + +// if ("n-href" in element.props) { +// props["n-href"] = fixLink(props["n-href"]); +// } + +// if ("n-src" in element.props) { +// props["n-src"] = fixLink(props["n-src"]); +// } + +// if ("src" in element.props) { +// props["src"] = fixLink(props.src); +// } + +// return React.cloneElement(element, props); +// } + +interface DomainLocale { + defaultLocale: string; + domain: string; + http?: true; + locales?: string[]; +} + +function renderDocument( + Document: DocumentType, + { + buildManifest, + docComponentsRendered, + props, + docProps, + pathname, + query, + buildId, + canonicalBase, + assetPrefix, + runtimeConfig, + nextExport, + autoExport, + isFallback, + dynamicImportsIds, + dangerousAsPath, + err, + dev, + ampPath, + ampState, + inAmpMode, + hybridAmp, + dynamicImports, + headTags, + gsp, + gssp, + customServer, + gip, + appGip, + unstable_runtimeJS, + unstable_JsPreload, + devOnlyCacheBusterQueryString, + scriptLoader, + locale, + locales, + defaultLocale, + domainLocales, + isPreview, + disableOptimizedLoading, + }: RenderOpts & { + props: any; + docComponentsRendered: DocumentProps["docComponentsRendered"]; + docProps: DocumentInitialProps; + pathname: string; + query: ParsedUrlQuery; + dangerousAsPath: string; + ampState: any; + ampPath: string; + inAmpMode: boolean; + hybridAmp: boolean; + dynamicImportsIds: (string | number)[]; + dynamicImports: string[]; + headTags: any; + isFallback?: boolean; + gsp?: boolean; + gssp?: boolean; + customServer?: boolean; + gip?: boolean; + appGip?: boolean; + devOnlyCacheBusterQueryString: string; + scriptLoader: any; + isPreview?: boolean; + autoExport?: boolean; + } +): string { + const htmlProps = { + __NEXT_DATA__: { + props, // The result of getInitialProps + page: pathname, // The rendered page + query, // querystring parsed / passed by the user + buildId, // buildId is used to facilitate caching of page bundles, we send it to the client so that pageloader knows where to load bundles + assetPrefix: assetPrefix === "" ? undefined : assetPrefix, // send assetPrefix to the client side when configured, otherwise don't sent in the resulting HTML + runtimeConfig, // runtimeConfig if provided, otherwise don't sent in the resulting HTML + nextExport, // If this is a page exported by `next export` + autoExport, // If this is an auto exported page + isFallback, + dynamicIds: + dynamicImportsIds.length === 0 ? undefined : dynamicImportsIds, + err: err || undefined, // err: err ? serializeError(dev, err) : undefined, // Error if one happened, otherwise don't sent in the resulting HTML + gsp, // whether the page is getStaticProps + gssp, // whether the page is getServerSideProps + customServer, // whether the user is using a custom server + gip, // whether the page has getInitialProps + appGip, // whether the _app has getInitialProps + locale, + locales, + defaultLocale, + domainLocales, + isPreview, + + pages: buildManifest.pages, + }, + buildManifest, + docComponentsRendered, + dangerousAsPath, + canonicalBase, + ampPath, + inAmpMode, + isDevelopment: !!dev, + hybridAmp, + dynamicImports, + assetPrefix, + headTags, + unstable_runtimeJS, + unstable_JsPreload, + devOnlyCacheBusterQueryString, + scriptLoader, + locale, + disableOptimizedLoading, + ...docProps, + }; + return ( + "<!DOCTYPE html>" + + ReactDOMServer.renderToStaticMarkup( + <AmpStateContext.Provider value={ampState}> + <HtmlContext.Provider value={htmlProps}> + <Document {...htmlProps} {...docProps}></Document> + </HtmlContext.Provider> + </AmpStateContext.Provider> + ) + ); +} + +class ServerRouter implements NextRouter { + route: string; + pathname: string; + query: ParsedUrlQuery; + asPath: string; + basePath: string; + events: any; + isFallback: boolean; + locale?: string; + isReady: boolean; + locales?: string[]; + defaultLocale?: string; + domainLocales?: DomainLocale[]; + isPreview: boolean; + isLocaleDomain: boolean; + + constructor( + pathname: string, + query: ParsedUrlQuery, + as: string, + { isFallback }: { isFallback: boolean }, + isReady: boolean, + basePath: string, + locale?: string, + locales?: string[], + defaultLocale?: string, + domainLocales?: DomainLocale[], + isPreview?: boolean, + isLocaleDomain?: boolean + ) { + this.route = pathname.replace(/\/$/, "") || "/"; + this.pathname = pathname; + this.query = query; + this.asPath = as; + this.isFallback = isFallback; + this.basePath = basePath; + this.locale = locale; + this.locales = locales; + this.defaultLocale = defaultLocale; + this.isReady = isReady; + this.domainLocales = domainLocales; + this.isPreview = !!isPreview; + this.isLocaleDomain = !!isLocaleDomain; + } + + push(): any { + noRouter(); + } + replace(): any { + noRouter(); + } + reload() { + noRouter(); + } + back() { + noRouter(); + } + prefetch(): any { + noRouter(); + } + beforePopState() { + noRouter(); + } +} + +function noRouter() { + const message = + 'No router instance found. you should only use "next/router" inside the client side of your app. https://nextjs.org/docs/messages/no-router-instance'; + throw new Error(message); +} + +function enhanceComponents( + options: ComponentsEnhancer, + App: AppType, + Component: NextComponentType +): { + App: AppType; + Component: NextComponentType; +} { + // For backwards compatibility + if (typeof options === "function") { + return { + App, + Component: options(Component), + }; + } + + return { + App: options.enhanceApp ? options.enhanceApp(App) : App, + Component: options.enhanceComponent + ? options.enhanceComponent(Component) + : Component, + }; +} + +Object.defineProperty(NextDocument.Head.prototype, "getScripts", { + get() { + return getScripts; + }, +}); +Object.defineProperty(NextDocument.NextScript.prototype, "getScripts", { + get() { + return getScripts; + }, +}); + +export async function render({ + route, + PageNamespace, + AppNamespace, + appStylesheets = [], + pageStylesheets = [], + DocumentNamespace = null, + buildId, + routePaths = [], +}: { + buildId: number; + route: any; + PageNamespace: { default: NextComponentType<any> }; + AppNamespace: { default: NextComponentType<any> } | null; + DocumentNamespace: Object | null; + appStylesheets: string[]; + pageStylesheets: string[]; + routePaths: string[]; +}): Promise<Response> { + const { default: Component, getStaticProps = null } = PageNamespace || {}; + const { default: AppComponent_ } = AppNamespace || {}; + var query = Object.assign({}, route.query); + + // These are reversed in our Router versus Next.js...mostly due to personal preference. + const pathname = "/" + route.name; + var asPath = route.pathname; + const pages = {}; + + for (let path of routePaths) { + const filePath = path.substring( + path.indexOf("_next/pages/") + "_next/pages".length + ); + const name = filePath.substring(0, filePath.indexOf(".")); + pages[name] = [path]; + } + + pages[pathname] = [route.scriptSrc, ...pageStylesheets]; + + if (appStylesheets.length > 0) { + if (pages["/_app"]) { + pages["/_app"].push(...appStylesheets); + } else { + pages["/_app"] = appStylesheets; + } + } + + const AppComponent = AppComponent_ || App.default; + const Document = + (DocumentNamespace && DocumentNamespace.default) || NextDocument.default; + // Document.Html.prototype.getScripts = getScripts; + // } + + const callMiddleware = async (method: string, args: any[], props = false) => { + let results: any = props ? {} : []; + + if ((Document as any)[`${method}Middleware`]) { + let middlewareFunc = await (Document as any)[`${method}Middleware`]; + middlewareFunc = middlewareFunc.default || middlewareFunc; + + const curResults = await middlewareFunc(...args); + if (props) { + for (const result of curResults) { + results = { + ...results, + ...result, + }; + } + } else { + results = curResults; + } + } + return results; + }; + + const headTags = (...args: any) => callMiddleware("headTags", args); + + if (!ReactIs.isValidElementType(Component)) { + const exportNames = Object.keys(PageNamespace || {}); + + const reactComponents = exportNames.filter(ReactIs.isValidElementType); + if (reactComponents.length > 2) { + throw new Error( + `\"export default\" missing in ${ + route.filePath + }.\nTry exporting one of ${reactComponents.join(", ")}\n` + ); + } else if (reactComponents.length === 2) { + throw new Error( + `\"export default\" missing in ${route.filePath}.\n\nTry exporting <${reactComponents[0]} /> or <${reactComponents[1]} />\n` + ); + } else if (reactComponents.length == 1) { + throw new Error( + `\"export default\" missing in ${route.filePath}. Try adding this to the bottom of the file:\n\n export default ${reactComponents[0]};\n` + ); + } else if (reactComponents.length == 0) { + throw new Error( + `\"export default\" missing in ${route.filePath}. Try exporting a React component.\n` + ); + } + } + + const isFallback = !!query.__nextFallback; + delete query.__nextFallback; + delete query.__nextLocale; + delete query.__nextDefaultLocale; + + const isSSG = !!getStaticProps; + const isBuildTimeSSG = isSSG && false; + const defaultAppGetInitialProps = + App.getInitialProps === (App as any).origGetInitialProps; + + const hasPageGetInitialProps = !!(Component as any).getInitialProps; + const pageIsDynamic = route.kind === "dynamic"; + const isAutoExport = false; + + if (isAutoExport || isFallback) { + // // remove query values except ones that will be set during export + // query = { + // ...(query.amp + // ? { + // amp: query.amp, + // } + // : {}), + // }; + asPath = `${asPath}${ + // ensure trailing slash is present for non-dynamic auto-export pages + asPath.endsWith("/") && asPath !== "/" && !pageIsDynamic ? "/" : "" + }`; + } + + let head: JSX.Element[] = [ + <meta charSet="utf-8" />, + <meta name="viewport" content="width=device-width" />, + ]; + + const nextExport = isAutoExport || isFallback; + const reactLoadableModules: string[] = []; + var scriptLoader = {}; + const AppContainer = ({ children }: any) => ( + <RouterContext.Provider value={router}> + {/* <AmpStateContext.Provider value={ampState}> */} + <HeadManagerContext.Provider + value={{ + updateHead: (state) => { + head = state; + }, + updateScripts: (scripts) => { + scriptLoader = scripts; + }, + scripts: {}, + mountedInstances: new Set(), + }} + > + <LoadableContext.Provider + value={(moduleName) => reactLoadableModules.push(moduleName)} + > + {children} + </LoadableContext.Provider> + </HeadManagerContext.Provider> + {/* </AmpStateContext.Provider> */} + </RouterContext.Provider> + ); + + await Loadable.preloadAll(); // Make sure all dynamic imports are loaded + + const router = new ServerRouter( + pathname, + query, + asPath, + { + isFallback: isFallback, + }, + true, + Bun.origin, + null, + [], // renderOpts.locales, + null, //renderOpts.defaultLocale, + [], // renderOpts.domainLocales, + false, + false + ); + + const ctx = { + err: null, + req: undefined, + res: undefined, + pathname, + query, + asPath, + locale: null, + locales: [], + defaultLocale: null, + AppTree: (props: any) => { + return ( + <AppContainer> + <App {...props} Component={Component} router={router} /> + </AppContainer> + ); + }, + }; + + var props = await loadGetInitialProps(AppComponent, { + AppTree: ctx.AppTree, + Component, + router, + ctx, + }); + + // This isn't correct. + // We don't call getServerSideProps on clients. + const getServerSideProps = PageNamespace.getServerSideProps; + if (typeof getServerSideProps === "function") { + const result = await getServerSideProps({ + params: route.params, + query: route.query, + req: notImplementedProxy("req"), + res: notImplementedProxy("res"), + resolvedUrl: route.pathname, + preview: false, + previewData: null, + locale: null, + locales: [], + defaultLocale: null, + }); + + if (result) { + if ("props" in result) { + if (typeof result.props === "object") { + Object.assign(props, result.props); + } + } + } + } + + const renderToString = ReactDOMServer.renderToString; + const ErrorDebug = null; + + const renderPage: RenderPage = ( + options: ComponentsEnhancer = {} + ): RenderPageResult | Promise<RenderPageResult> => { + if (ctx.err && ErrorDebug) { + const htmlOrPromise = renderToString(<ErrorDebug error={ctx.err} />); + return typeof htmlOrPromise === "string" + ? { html: htmlOrPromise, head } + : htmlOrPromise.then((html) => ({ + html, + head, + })); + } + + if (dev && (props.router || props.Component)) { + throw new Error( + `'router' and 'Component' can not be returned in getInitialProps from _app.js https://nextjs.org/docs/messages/cant-override-next-props` + ); + } + + const { App: EnhancedApp, Component: EnhancedComponent } = + enhanceComponents(options, AppComponent, Component); + + const htmlOrPromise = renderToString( + <AppContainer> + <EnhancedApp Component={EnhancedComponent} router={router} {...props} /> + </AppContainer> + ); + return typeof htmlOrPromise === "string" + ? { html: htmlOrPromise, head } + : htmlOrPromise.then((html) => ({ + html, + head, + })); + }; + + const documentCtx = { ...ctx, renderPage }; + const docProps: DocumentInitialProps = await loadGetInitialProps( + Document, + documentCtx + ); + + if (!docProps || typeof docProps.html !== "string") { + const message = `"${getDisplayName( + Document + )}.getInitialProps()" should resolve to an object with a "html" prop set with a valid html string`; + throw new Error(message); + } + + const renderOpts = { + params: route.params, + }; + // renderOpts.params = _params || params; + + // parsedUrl.pathname = denormalizePagePath(parsedUrl.pathname!); + // renderOpts.resolvedUrl = formatUrl({ + // ...parsedUrl, + // query: origQuery, + // }); + const docComponentsRendered: DocumentProps["docComponentsRendered"] = {}; + + const isPreview = false; + + let html = renderDocument(Document, { + docComponentsRendered, + ...renderOpts, + disableOptimizedLoading: false, + canonicalBase: Bun.origin, + buildManifest: { + devFiles: [], + allFiles: [], + polyfillFiles: [], + lowPriorityFiles: [], + pages: pages, + }, + // Only enabled in production as development mode has features relying on HMR (style injection for example) + unstable_runtimeJS: true, + // process.env.NODE_ENV === "production" + // ? pageConfig.unstable_runtimeJS + // : undefined, + // unstable_JsPreload: pageConfig.unstable_JsPreload, + unstable_JsPreload: true, + dangerousAsPath: router.asPath, + ampState: undefined, + props, + assetPrefix: "", + headTags: await headTags(documentCtx), + isFallback, + docProps, + pathname, + ampPath: undefined, + query, + inAmpMode: false, + hybridAmp: undefined, + dynamicImportsIds: [], // Array.from(dynamicImportsIds), + dynamicImports: [], //Array.from(dynamicImports), + gsp: !!getStaticProps ? true : undefined, + gssp: !!getServerSideProps ? true : undefined, + gip: hasPageGetInitialProps ? true : undefined, + appGip: !defaultAppGetInitialProps ? true : undefined, + devOnlyCacheBusterQueryString: "", + scriptLoader, + isPreview: isPreview === true ? true : undefined, + autoExport: isAutoExport === true ? true : undefined, + nextExport: nextExport === true ? true : undefined, + }); + const bodyRenderIdx = html.indexOf(BODY_RENDER_TARGET); + html = + html.substring(0, bodyRenderIdx) + + (false ? "<!-- __NEXT_DATA__ -->" : "") + + docProps.html + + html.substring(bodyRenderIdx + BODY_RENDER_TARGET.length); + return new Response( + html + .replaceAll("/_next/http://", "http://") + .replaceAll("/_next/https://", "https://") + ); +} diff --git a/examples/hello-next/bun-framework-next/route-loader.ts b/examples/hello-next/bun-framework-next/route-loader.ts new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/examples/hello-next/bun-framework-next/route-loader.ts diff --git a/examples/hello-next/bun-framework-next/server.development.tsx b/examples/hello-next/bun-framework-next/server.development.tsx new file mode 100644 index 000000000..e3cd24e01 --- /dev/null +++ b/examples/hello-next/bun-framework-next/server.development.tsx @@ -0,0 +1,79 @@ +import * as React from "react"; +import { Buffer } from "buffer"; +globalThis.Buffer = Buffer; + +class URL { + constructor(base, source) { + this.pathname = source; + this.href = base + source; + } +} +var onlyChildPolyfill = React.Children.only; +React.Children.only = function (children) { + if (children && typeof children === "object" && children.length == 1) { + return onlyChildPolyfill(children[0]); + } + + return onlyChildPolyfill(children); +}; +globalThis.URL = URL; +globalThis.global = globalThis; +import { render } from "./renderDocument"; + +let buildId = 0; + +var DocumentLoaded = false; +var DocumentNamespace; + +import(Bun.routesDir + "_document").then( + (doc) => { + DocumentNamespace = doc; + DocumentLoaded = true; + }, + (err) => { + if (err instanceof ResolveError) { + DocumentLoaded = true; + } else { + console.error(err); + } + } +); + +addEventListener("fetch", async (event: FetchEvent) => { + var route = Bun.match(event); + + // This imports the currently matched route. + const PageNamespace = 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 pageStylesheets = (Bun.getImportedStyles() as string[]).slice(); + + var appRoute; + + try { + appRoute = await import(Bun.routesDir + "_app"); + } catch (exception) { + appRoute = null; + } + const appStylesheets = (Bun.getImportedStyles() as string[]).slice(); + + event.respondWith( + render({ + route, + PageNamespace, + appStylesheets, + pageStylesheets, + DocumentNamespace, + AppNamespace: appRoute, + buildId, + routePaths: Bun.getRouteFiles(), + }) + ); + buildId++; +}); + +// typescript isolated modules +export {}; + +declare var Bun: any; diff --git a/examples/hello-next/bun-framework-next/server.production.tsx b/examples/hello-next/bun-framework-next/server.production.tsx new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/examples/hello-next/bun-framework-next/server.production.tsx diff --git a/examples/hello-next/bun-framework-next/tsconfig.json b/examples/hello-next/bun-framework-next/tsconfig.json new file mode 100644 index 000000000..d14767c9f --- /dev/null +++ b/examples/hello-next/bun-framework-next/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "esnext", + "lib": ["dom", "dom.iterable", "esnext", "WebWorker"], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "baseUrl": ".", + "paths": {} + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/examples/hello-next/package.json b/examples/hello-next/package.json index 77ce7b80e..aacc87742 100644 --- a/examples/hello-next/package.json +++ b/examples/hello-next/package.json @@ -6,9 +6,10 @@ "dependencies": { "next": "^11.1.0", "parcel": "2.0.0-rc.0", - "path": "^0.12.7", + "path-browserify": "^1.0.1", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-is": "^17.0.2", "whatwg-url": "^9.1.0" }, "devDependencies": { diff --git a/examples/hello-next/pages/errortest.tsx b/examples/hello-next/pages/errortest.tsx new file mode 100644 index 000000000..49a293df7 --- /dev/null +++ b/examples/hello-next/pages/errortest.tsx @@ -0,0 +1,14 @@ +import IndexPage from "pages/index"; + +export default function ErrorTestPage() { + class Wow {} + + const ladee = "", + foo = { bar: { boom: new Wow() } }; + + if (typeof window === "undefined") { + const Doge = import("wow/such-esm/very-import"); + } + + return <IndexPage />; +} diff --git a/examples/hello-next/pages/index.tsx b/examples/hello-next/pages/index.tsx index dab661672..7a2eb9f64 100644 --- a/examples/hello-next/pages/index.tsx +++ b/examples/hello-next/pages/index.tsx @@ -3,10 +3,10 @@ import Image from "next/image"; import styles from "../styles/Home.module.css"; import Link from "next/link"; import { useRouter } from "next/router"; -import Title from "../components/Title"; +import Title, { TitleEnum } from "../components/Title"; import React from "react"; -export default function Home() { +export default function Home({}) { const router = useRouter(); return ( @@ -17,11 +17,9 @@ export default function Home() { <link rel="icon" href="/favicon.ico" /> </Head> - <Title /> - <main className={styles.main}> <h1 className={styles.title}> - asdasdasd to <a href="https://nextjs.org">Next.js!</a> + Welcome to <a href="https://nextjs.org">Next.js!</a> </h1> <p className={styles.description}> @@ -37,14 +35,13 @@ export default function Home() { </div> </Link> - <button + <a onClick={() => router.push("/foo/bar/third")} className={styles.card} - style={{ backgroundColor: "white" }} > <h2>Third Page →</h2> <p>button, router.push()</p> - </button> + </a> <a href="https://github.com/vercel/next.js/tree/master/examples" diff --git a/examples/hello-next/styles/2.css b/examples/hello-next/styles/2.css index 1e30d2166..e69de29bb 100644 --- a/examples/hello-next/styles/2.css +++ b/examples/hello-next/styles/2.css @@ -1,3 +0,0 @@ -* { - background-color: red; -} diff --git a/examples/hello-next/styles/globals.css b/examples/hello-next/styles/globals.css index e5e2dcc23..1abf383f1 100644 --- a/examples/hello-next/styles/globals.css +++ b/examples/hello-next/styles/globals.css @@ -14,3 +14,8 @@ a { * { box-sizing: border-box; } + +body { + background-image: url(https://wompampsupport.azureedge.net/fetchimage?siteId=7575&v=2&jpgQuality=100&width=700&url=https%3A%2F%2Fi.kym-cdn.com%2Fentries%2Ficons%2Foriginal%2F000%2F013%2F564%2Fdoge.jpg); + background-size: cover; +} diff --git a/examples/hello-next/tsconfig.json b/examples/hello-next/tsconfig.json index b423bb201..7af6240a5 100644 --- a/examples/hello-next/tsconfig.json +++ b/examples/hello-next/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "target": "esnext", - "lib": ["dom", "dom.iterable", "esnext", "WebWorker"], + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": false, @@ -9,15 +9,13 @@ "noEmit": true, "esModuleInterop": true, "module": "esnext", - "moduleResolution": "Node", + "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "baseUrl": ".", - "paths": { - "path": ["node_modules/path-browserify"] - } + "paths": {} }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/index.tsx"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"] } diff --git a/examples/lotta-modules/index.js b/examples/lotta-modules/index.js index 4968cac4b..e86d5e2d8 100644 --- a/examples/lotta-modules/index.js +++ b/examples/lotta-modules/index.js @@ -1,641 +1,11 @@ -import "lodash/_DataView.js"; -import "lodash/_Hash.js"; -import "lodash/_LazyWrapper.js"; -import "lodash/_ListCache"; -import "lodash/_LodashWrapper.js"; -import "lodash/_Map.js"; -import "lodash/_MapCache.js"; -import "lodash/_Promise.js"; -import "lodash/_Set.js"; -import "lodash/_SetCache.js"; -import "lodash/_Stack.js"; -import "lodash/_Symbol.js"; -import "lodash/_Uint8Array.js"; -import "lodash/_WeakMap.js"; -import "lodash/_apply.js"; -import "lodash/_arrayAggregator.js"; -import "lodash/_arrayEach.js"; -import "lodash/_arrayEachRight.js"; -import "lodash/_arrayEvery.js"; -import "lodash/_arrayFilter.js"; -import "lodash/_arrayIncludes.js"; -import "lodash/_arrayIncludesWith.js"; -import "lodash/_arrayLikeKeys.js"; -import "lodash/_arrayMap.js"; -import "lodash/_arrayPush.js"; -import "lodash/_arrayReduce.js"; -import "lodash/_arrayReduceRight.js"; -import "lodash/_arraySample.js"; -import "lodash/_arraySampleSize.js"; -import "lodash/_arrayShuffle.js"; -import "lodash/_arraySome.js"; -import "lodash/_asciiSize.js"; -import "lodash/_asciiToArray.js"; -import "lodash/_asciiWords.js"; -import "lodash/_assignMergeValue.js"; -import "lodash/_assignValue.js"; -import "lodash/_assocIndexOf.js"; -import "lodash/_baseAggregator.js"; -import "lodash/_baseAssign.js"; -import "lodash/_baseAssignIn.js"; -import "lodash/_baseAssignValue.js"; -import "lodash/_baseAt.js"; -import "lodash/_baseClamp.js"; -import "lodash/_baseClone.js"; -import "lodash/_baseConforms.js"; -import "lodash/_baseConformsTo.js"; -import "lodash/_baseCreate.js"; -import "lodash/_baseDelay.js"; -import "lodash/_baseDifference.js"; -import "lodash/_baseEach.js"; -import "lodash/_baseEachRight.js"; -import "lodash/_baseEvery.js"; -import "lodash/_baseExtremum.js"; -import "lodash/_baseFill.js"; -import "lodash/_baseFilter.js"; -import "lodash/_baseFindIndex.js"; -import "lodash/_baseFindKey.js"; -import "lodash/_baseFlatten.js"; -import "lodash/_baseFor.js"; -import "lodash/_baseForOwn.js"; -import "lodash/_baseForOwnRight.js"; -import "lodash/_baseForRight.js"; -import "lodash/_baseFunctions.js"; -import "lodash/_baseGet.js"; -import "lodash/_baseGetAllKeys.js"; -import "lodash/_baseGetTag.js"; -import "lodash/_baseGt.js"; -import "lodash/_baseHas.js"; -import "lodash/_baseHasIn.js"; -import "lodash/_baseInRange.js"; -import "lodash/_baseIndexOf.js"; -import "lodash/_baseIndexOfWith.js"; -import "lodash/_baseIntersection.js"; -import "lodash/_baseInverter.js"; -import "lodash/_baseInvoke.js"; -import "lodash/_baseIsArguments.js"; -import "lodash/_baseIsArrayBuffer.js"; -import "lodash/_baseIsDate.js"; -import "lodash/_baseIsEqual.js"; -import "lodash/_baseIsEqualDeep.js"; -import "lodash/_baseIsMap.js"; -import "lodash/_baseIsMatch.js"; -import "lodash/_baseIsNaN.js"; -import "lodash/_baseIsNative.js"; -import "lodash/_baseIsRegExp.js"; -import "lodash/_baseIsSet.js"; -import "lodash/_baseIsTypedArray.js"; -import "lodash/_baseIteratee.js"; -import "lodash/_baseKeys.js"; -import "lodash/_baseKeysIn.js"; -import "lodash/_baseLodash.js"; -import "lodash/_baseLt.js"; -import "lodash/_baseMap.js"; -import "lodash/_baseMatches.js"; -import "lodash/_baseMatchesProperty.js"; -import "lodash/_baseMean.js"; -import "lodash/_baseMerge.js"; -import "lodash/_baseMergeDeep.js"; -import "lodash/_baseNth.js"; -import "lodash/_baseOrderBy.js"; -import "lodash/_basePick.js"; -import "lodash/_basePickBy.js"; -import "lodash/_baseProperty.js"; -import "lodash/_basePropertyDeep.js"; -import "lodash/_basePropertyOf.js"; -import "lodash/_basePullAll.js"; -import "lodash/_basePullAt.js"; -import "lodash/_baseRandom.js"; -import "lodash/_baseRange.js"; -import "lodash/_baseReduce.js"; -import "lodash/_baseRepeat.js"; -import "lodash/_baseRest.js"; -import "lodash/_baseSample.js"; -import "lodash/_baseSampleSize.js"; -import "lodash/_baseSet.js"; -import "lodash/_baseSetData.js"; -import "lodash/_baseSetToString.js"; -import "lodash/_baseShuffle.js"; -import "lodash/_baseSlice.js"; -import "lodash/_baseSome.js"; -import "lodash/_baseSortBy.js"; -import "lodash/_baseSortedIndex.js"; -import "lodash/_baseSortedIndexBy.js"; -import "lodash/_baseSortedUniq.js"; -import "lodash/_baseSum.js"; -import "lodash/_baseTimes.js"; -import "lodash/_baseToNumber.js"; -import "lodash/_baseToPairs.js"; -import "lodash/_baseToString.js"; -import "lodash/_baseTrim.js"; -import "lodash/_baseUnary.js"; -import "lodash/_baseUniq.js"; -import "lodash/_baseUnset.js"; -import "lodash/_baseUpdate.js"; -import "lodash/_baseValues.js"; -import "lodash/_baseWhile.js"; -import "lodash/_baseWrapperValue.js"; -import "lodash/_baseXor.js"; -import "lodash/_baseZipObject.js"; -import "lodash/_cacheHas.js"; -import "lodash/_castArrayLikeObject.js"; -import "lodash/_castFunction.js"; -import "lodash/_castPath.js"; -import "lodash/_castRest.js"; -import "lodash/_castSlice.js"; -import "lodash/_charsEndIndex.js"; -import "lodash/_charsStartIndex.js"; -import "lodash/_cloneArrayBuffer.js"; -import "lodash/_cloneBuffer.js"; -import "lodash/_cloneDataView.js"; -import "lodash/_cloneRegExp.js"; -import "lodash/_cloneSymbol.js"; -import "lodash/_cloneTypedArray.js"; -import "lodash/_compareAscending.js"; -import "lodash/_compareMultiple.js"; -import "lodash/_composeArgs.js"; -import "lodash/_composeArgsRight.js"; -import "lodash/_copyArray.js"; -import "lodash/_copyObject.js"; -import "lodash/_copySymbols.js"; -import "lodash/_copySymbolsIn.js"; -import "lodash/_coreJsData.js"; -import "lodash/_countHolders.js"; -import "lodash/_createAggregator.js"; -import "lodash/_createAssigner.js"; -import "lodash/_createBaseEach.js"; -import "lodash/_createBaseFor.js"; -import "lodash/_createBind.js"; -import "lodash/_createCaseFirst.js"; -import "lodash/_createCompounder.js"; -import "lodash/_createCtor.js"; -import "lodash/_createCurry.js"; -import "lodash/_createFind.js"; -import "lodash/_createFlow.js"; -import "lodash/_createHybrid.js"; -import "lodash/_createInverter.js"; -import "lodash/_createMathOperation.js"; -import "lodash/_createOver.js"; -import "lodash/_createPadding.js"; -import "lodash/_createPartial.js"; -import "lodash/_createRange.js"; -import "lodash/_createRecurry.js"; -import "lodash/_createRelationalOperation.js"; -import "lodash/_createRound.js"; -import "lodash/_createSet.js"; -import "lodash/_createToPairs.js"; -import "lodash/_createWrap.js"; -import "lodash/_customDefaultsAssignIn.js"; -import "lodash/_customDefaultsMerge.js"; -import "lodash/_customOmitClone.js"; -import "lodash/_deburrLetter.js"; -import "lodash/_defineProperty.js"; -import "lodash/_equalArrays.js"; -import "lodash/_equalByTag.js"; -import "lodash/_equalObjects.js"; -import "lodash/_escapeHtmlChar.js"; -import "lodash/_escapeStringChar.js"; -import "lodash/_flatRest.js"; -import "lodash/_freeGlobal.js"; -import "lodash/_getAllKeys.js"; -import "lodash/_getAllKeysIn.js"; -import "lodash/_getData.js"; -import "lodash/_getFuncName.js"; -import "lodash/_getHolder.js"; -import "lodash/_getMapData.js"; -import "lodash/_getMatchData.js"; -import "lodash/_getNative.js"; -import "lodash/_getPrototype.js"; -import "lodash/_getRawTag.js"; -import "lodash/_getSymbols.js"; -import "lodash/_getSymbolsIn.js"; -import "lodash/_getTag.js"; -import "lodash/_getValue.js"; -import "lodash/_getView.js"; -import "lodash/_getWrapDetails.js"; -import "lodash/_hasPath.js"; -import "lodash/_hasUnicode.js"; -import "lodash/_hasUnicodeWord.js"; -import "lodash/_hashClear.js"; -import "lodash/_hashDelete.js"; -import "lodash/_hashGet.js"; -import "lodash/_hashHas.js"; -import "lodash/_hashSet.js"; -import "lodash/_initCloneArray.js"; -import "lodash/_initCloneByTag.js"; -import "lodash/_initCloneObject.js"; -import "lodash/_insertWrapDetails.js"; -import "lodash/_isFlattenable.js"; -import "lodash/_isIndex.js"; -import "lodash/_isIterateeCall.js"; -import "lodash/_isKey.js"; -import "lodash/_isKeyable.js"; -import "lodash/_isLaziable.js"; -import "lodash/_isMaskable.js"; -import "lodash/_isMasked.js"; -import "lodash/_isPrototype.js"; -import "lodash/_isStrictComparable.js"; -import "lodash/_iteratorToArray.js"; -import "lodash/_lazyClone.js"; -import "lodash/_lazyReverse.js"; -import "lodash/_lazyValue.js"; -import "lodash/_listCacheClear.js"; -import "lodash/_listCacheDelete.js"; -import "lodash/_listCacheGet.js"; -import "lodash/_listCacheHas.js"; -import "lodash/_listCacheSet.js"; -import "lodash/_mapCacheClear.js"; -import "lodash/_mapCacheDelete.js"; -import "lodash/_mapCacheGet.js"; -import "lodash/_mapCacheHas.js"; -import "lodash/_mapCacheSet.js"; -import "lodash/_mapToArray.js"; -import "lodash/_matchesStrictComparable.js"; -import "lodash/_memoizeCapped.js"; -import "lodash/_mergeData.js"; -import "lodash/_metaMap.js"; -import "lodash/_nativeCreate.js"; -import "lodash/_nativeKeys.js"; -import "lodash/_nativeKeysIn.js"; -import "lodash/_nodeUtil.js"; -import "lodash/_objectToString.js"; -import "lodash/_overArg.js"; -import "lodash/_overRest.js"; -import "lodash/_parent.js"; -import "lodash/_reEscape.js"; -import "lodash/_reEvaluate.js"; -import "lodash/_reInterpolate.js"; -import "lodash/_realNames.js"; -import "lodash/_reorder.js"; -import "lodash/_replaceHolders.js"; -import "lodash/_root.js"; -import "lodash/_safeGet.js"; -import "lodash/_setCacheAdd.js"; -import "lodash/_setCacheHas.js"; -import "lodash/_setData.js"; -import "lodash/_setToArray.js"; -import "lodash/_setToPairs.js"; -import "lodash/_setToString.js"; -import "lodash/_setWrapToString.js"; -import "lodash/_shortOut.js"; -import "lodash/_shuffleSelf.js"; -import "lodash/_stackClear.js"; -import "lodash/_stackDelete.js"; -import "lodash/_stackGet.js"; -import "lodash/_stackHas.js"; -import "lodash/_stackSet.js"; -import "lodash/_strictIndexOf.js"; -import "lodash/_strictLastIndexOf.js"; -import "lodash/_stringSize.js"; -import "lodash/_stringToArray.js"; -import "lodash/_stringToPath.js"; -import "lodash/_toKey.js"; -import "lodash/_toSource.js"; -import "lodash/_trimmedEndIndex.js"; -import "lodash/_unescapeHtmlChar.js"; -import "lodash/_unicodeSize.js"; -import "lodash/_unicodeToArray.js"; -import "lodash/_unicodeWords.js"; -import "lodash/_updateWrapDetails.js"; -import "lodash/_wrapperClone.js"; -import "lodash/add.js"; -import "lodash/after.js"; -import "lodash/array.js"; -import "lodash/ary.js"; -import "lodash/assign.js"; -import "lodash/assignIn.js"; -import "lodash/assignInWith.js"; -import "lodash/assignWith.js"; -import "lodash/at.js"; -import "lodash/attempt.js"; -import "lodash/before.js"; -import "lodash/bind.js"; -import "lodash/bindAll.js"; -import "lodash/bindKey.js"; -import "lodash/camelCase.js"; -import "lodash/capitalize.js"; -import "lodash/castArray.js"; -import "lodash/ceil.js"; -import "lodash/chain.js"; -import "lodash/chunk.js"; -import "lodash/clamp.js"; -import "lodash/clone.js"; -import "lodash/cloneDeep.js"; -import "lodash/cloneDeepWith.js"; -import "lodash/cloneWith.js"; -import "lodash/collection.js"; -import "lodash/commit.js"; -import "lodash/compact.js"; -import "lodash/concat.js"; -import "lodash/cond.js"; -import "lodash/conforms.js"; -import "lodash/conformsTo.js"; -import "lodash/constant.js"; -import "lodash/core.js"; -import "lodash/core.min.js"; -import "lodash/countBy.js"; -import "lodash/create.js"; -import "lodash/curry.js"; -import "lodash/curryRight.js"; -import "lodash/date.js"; -import "lodash/debounce.js"; -import "lodash/deburr.js"; -import "lodash/defaultTo.js"; -import "lodash/defaults.js"; -import "lodash/defaultsDeep.js"; -import "lodash/defer.js"; -import "lodash/delay.js"; -import "lodash/difference.js"; -import "lodash/differenceBy.js"; -import "lodash/differenceWith.js"; -import "lodash/divide.js"; -import "lodash/drop.js"; -import "lodash/dropRight.js"; -import "lodash/dropRightWhile.js"; -import "lodash/dropWhile.js"; -import "lodash/each.js"; -import "lodash/eachRight.js"; -import "lodash/endsWith.js"; -import "lodash/entries.js"; -import "lodash/entriesIn.js"; -import "lodash/eq.js"; -import "lodash/escape.js"; -import "lodash/escapeRegExp.js"; -import "lodash/every.js"; -import "lodash/extend.js"; -import "lodash/extendWith.js"; -import "lodash/fill.js"; -import "lodash/filter.js"; -import "lodash/find.js"; -import "lodash/findIndex.js"; -import "lodash/findKey.js"; -import "lodash/findLast.js"; -import "lodash/findLastIndex.js"; -import "lodash/findLastKey.js"; -import "lodash/first.js"; -import "lodash/flatMap.js"; -import "lodash/flatMapDeep.js"; -import "lodash/flatMapDepth.js"; -import "lodash/flatten.js"; -import "lodash/flattenDeep.js"; -import "lodash/flattenDepth.js"; -import "lodash/flip.js"; -import "lodash/floor.js"; -import "lodash/flow.js"; -import "lodash/flowRight.js"; -import "lodash/forEach.js"; -import "lodash/forEachRight.js"; -import "lodash/forIn.js"; -import "lodash/forInRight.js"; -import "lodash/forOwn.js"; -import "lodash/forOwnRight.js"; -import "lodash/fp"; -import "lodash/fp.js"; -import "lodash/fromPairs.js"; -import "lodash/function.js"; -import "lodash/functions.js"; -import "lodash/functionsIn.js"; -import "lodash/get.js"; -import "lodash/groupBy.js"; -import "lodash/gt.js"; -import "lodash/gte.js"; -import "lodash/has.js"; -import "lodash/hasIn.js"; -import "lodash/head.js"; -import "lodash/identity.js"; -import "lodash/inRange.js"; -import "lodash/includes.js"; -import "lodash/index.js"; -import "lodash/indexOf.js"; -import "lodash/initial.js"; -import "lodash/intersection.js"; -import "lodash/intersectionBy.js"; -import "lodash/intersectionWith.js"; -import "lodash/invert.js"; -import "lodash/invertBy.js"; -import "lodash/invoke.js"; -import "lodash/invokeMap.js"; -import "lodash/isArguments.js"; -import "lodash/isArray.js"; -import "lodash/isArrayBuffer.js"; -import "lodash/isArrayLike.js"; -import "lodash/isArrayLikeObject.js"; -import "lodash/isBoolean.js"; -import "lodash/isBuffer.js"; -import "lodash/isDate.js"; -import "lodash/isElement.js"; -import "lodash/isEmpty.js"; -import "lodash/isEqual.js"; -import "lodash/isEqualWith.js"; -import "lodash/isError.js"; -import "lodash/isFinite.js"; -import "lodash/isFunction.js"; -import "lodash/isInteger.js"; -import "lodash/isLength.js"; -import "lodash/isMap.js"; -import "lodash/isMatch.js"; -import "lodash/isMatchWith.js"; -import "lodash/isNaN.js"; -import "lodash/isNative.js"; -import "lodash/isNil.js"; -import "lodash/isNull.js"; -import "lodash/isNumber.js"; -import "lodash/isObject.js"; -import "lodash/isObjectLike.js"; -import "lodash/isPlainObject.js"; -import "lodash/isRegExp.js"; -import "lodash/isSafeInteger.js"; -import "lodash/isSet.js"; -import "lodash/isString.js"; -import "lodash/isSymbol.js"; -import "lodash/isTypedArray.js"; -import "lodash/isUndefined.js"; -import "lodash/isWeakMap.js"; -import "lodash/isWeakSet.js"; -import "lodash/iteratee.js"; -import "lodash/join.js"; -import "lodash/kebabCase.js"; -import "lodash/keyBy.js"; -import "lodash/keys.js"; -import "lodash/keysIn.js"; -import "lodash/lang.js"; -import "lodash/last.js"; -import "lodash/lastIndexOf.js"; -import "lodash/lodash.js"; -import "lodash/lodash.min.js"; -import "lodash/lowerCase.js"; -import "lodash/lowerFirst.js"; -import "lodash/lt.js"; -import "lodash/lte.js"; -import "lodash/map.js"; -import "lodash/mapKeys.js"; -import "lodash/mapValues.js"; -import "lodash/matches.js"; -import "lodash/matchesProperty.js"; -import "lodash/math.js"; -import "lodash/max.js"; -import "lodash/maxBy.js"; -import "lodash/mean.js"; -import "lodash/meanBy.js"; -import "lodash/memoize.js"; -import "lodash/merge.js"; -import "lodash/mergeWith.js"; -import "lodash/method.js"; -import "lodash/methodOf.js"; -import "lodash/min.js"; -import "lodash/minBy.js"; -import "lodash/mixin.js"; -import "lodash/multiply.js"; -import "lodash/negate.js"; -import "lodash/next.js"; -import "lodash/noop.js"; -import "lodash/now.js"; -import "lodash/nth.js"; -import "lodash/nthArg.js"; -import "lodash/number.js"; -import "lodash/object.js"; -import "lodash/omit.js"; -import "lodash/omitBy.js"; -import "lodash/once.js"; -import "lodash/orderBy.js"; -import "lodash/over.js"; -import "lodash/overArgs.js"; -import "lodash/overEvery.js"; -import "lodash/overSome.js"; -import "lodash/pad.js"; -import "lodash/padEnd.js"; -import "lodash/padStart.js"; -import "lodash/parseInt.js"; -import "lodash/partial.js"; -import "lodash/partialRight.js"; -import "lodash/partition.js"; -import "lodash/pick.js"; -import "lodash/pickBy.js"; -import "lodash/plant.js"; -import "lodash/property.js"; -import "lodash/propertyOf.js"; -import "lodash/pull.js"; -import "lodash/pullAll.js"; -import "lodash/pullAllBy.js"; -import "lodash/pullAllWith.js"; -import "lodash/pullAt.js"; -import "lodash/random.js"; -import "lodash/range.js"; -import "lodash/rangeRight.js"; -import "lodash/rearg.js"; -import "lodash/reduce.js"; -import "lodash/reduceRight.js"; -import "lodash/reject.js"; -import "lodash/remove.js"; -import "lodash/repeat.js"; -import "lodash/replace.js"; -import "lodash/rest.js"; -import "lodash/result.js"; -import "lodash/reverse.js"; -import "lodash/round.js"; -import "lodash/sample.js"; -import "lodash/sampleSize.js"; -import "lodash/seq.js"; -import "lodash/set.js"; -import "lodash/setWith.js"; -import "lodash/shuffle.js"; -import "lodash/size.js"; -import "lodash/slice.js"; -import "lodash/snakeCase.js"; -import "lodash/some.js"; -import "lodash/sortBy.js"; -import "lodash/sortedIndex.js"; -import "lodash/sortedIndexBy.js"; -import "lodash/sortedIndexOf.js"; -import "lodash/sortedLastIndex.js"; -import "lodash/sortedLastIndexBy.js"; -import "lodash/sortedLastIndexOf.js"; -import "lodash/sortedUniq.js"; -import "lodash/sortedUniqBy.js"; -import "lodash/split.js"; -import "lodash/spread.js"; -import "lodash/startCase.js"; -import "lodash/startsWith.js"; -import "lodash/string.js"; -import "lodash/stubArray.js"; -import "lodash/stubFalse.js"; -import "lodash/stubObject.js"; -import "lodash/stubString.js"; -import "lodash/stubTrue.js"; -import "lodash/subtract.js"; -import "lodash/sum.js"; -import "lodash/sumBy.js"; -import "lodash/tail.js"; -import "lodash/take.js"; -import "lodash/takeRight.js"; -import "lodash/takeRightWhile.js"; -import "lodash/takeWhile.js"; -import "lodash/tap.js"; -import "lodash/template.js"; -import "lodash/templateSettings.js"; -import "lodash/throttle.js"; -import "lodash/thru.js"; -import "lodash/times.js"; -import "lodash/toArray.js"; -import "lodash/toFinite.js"; -import "lodash/toInteger.js"; -import "lodash/toIterator.js"; -import "lodash/toJSON.js"; -import "lodash/toLength.js"; -import "lodash/toLower.js"; -import "lodash/toNumber.js"; -import "lodash/toPairs.js"; -import "lodash/toPairsIn.js"; -import "lodash/toPath.js"; -import "lodash/toPlainObject.js"; -import "lodash/toSafeInteger.js"; -import "lodash/toString.js"; -import "lodash/toUpper.js"; -import "lodash/transform.js"; -import "lodash/trim.js"; -import "lodash/trimEnd.js"; -import "lodash/trimStart.js"; -import "lodash/truncate.js"; -import "lodash/unary.js"; -import "lodash/unescape.js"; -import "lodash/union.js"; -import "lodash/unionBy.js"; -import "lodash/unionWith.js"; -import "lodash/uniq.js"; -import "lodash/uniqBy.js"; -import "lodash/uniqWith.js"; -import "lodash/uniqueId.js"; -import "lodash/unset.js"; -import "lodash/unzip.js"; -import "lodash/unzipWith.js"; -import "lodash/update.js"; -import "lodash/updateWith.js"; -import "lodash/upperCase.js"; -import "lodash/upperFirst.js"; -import "lodash/util.js"; -import "lodash/value.js"; -import "lodash/valueOf.js"; -import "lodash/values.js"; -import "lodash/valuesIn.js"; -import "lodash/without.js"; -import "lodash/words.js"; -import "lodash/wrap.js"; -import "lodash/wrapperAt.js"; -import "lodash/wrapperChain.js"; -import "lodash/wrapperLodash.js"; -import "lodash/wrapperReverse.js"; -import "lodash/wrapperValue.js"; -import "lodash/xor.js"; -import "lodash/xorBy.js"; -import "lodash/xorWith.js"; -import "lodash/zip.js"; -import "lodash/zipObject.js"; -import "lodash/zipObjectDeep.js"; -import "lodash/_setToString"; -import "lodash"; -import "lodash/lodash"; - -import "underscore"; -import "three"; - -// import "@babel/standalone/babel.js"; +import "three/three1"; +import "three/three2"; +import "three/three3"; +import "three/three4"; +import "three/three5"; +import "three/three6"; +import "three/three7"; +import "three/three8"; +import "three/three9"; +import "three/three10"; +// import "@babel/standalone/babel"; diff --git a/examples/lotta-modules/public/index.html b/examples/lotta-modules/public/index.html new file mode 100644 index 000000000..bb6a38234 --- /dev/null +++ b/examples/lotta-modules/public/index.html @@ -0,0 +1,6 @@ +<html> + <head> </head> + <body> + <script src="/index.js"></script> + </body> +</html> |