diff --git a/src/Playground.res b/src/Playground.res index f20a1f633..b11f75250 100644 --- a/src/Playground.res +++ b/src/Playground.res @@ -1419,7 +1419,7 @@ module App = { let initialReContent = `Js.log("Hello Reason 3.6!");` @react.component -let make = (~versions: array) => { +let make = (~bundleBaseUrl: string, ~versions: array) => { let router = Next.Router.useRouter() let versions = @@ -1436,14 +1436,18 @@ let make = (~versions: array) => { cmp(b) - cmp(a) }) - let lastStableVersion = versions->Array.find(version => version.preRelease->Option.isNone) - - let initialVersion = switch Dict.get(router.query, "version") { - | Some(version) => version->Semver.parse - | None => - switch Url.getVersionFromStorage(Playground) { - | Some(v) => v->Semver.parse - | None => lastStableVersion + let initialVersion = switch versions { + | [v] => Some(v) // only single version available. maybe local dev. + | versions => { + let lastStableVersion = versions->Array.find(version => version.preRelease->Option.isNone) + switch Dict.get(router.query, "version") { + | Some(version) => version->Semver.parse + | None => + switch Url.getVersionFromStorage(Playground) { + | Some(v) => v->Semver.parse + | None => lastStableVersion + } + } } } @@ -1470,6 +1474,7 @@ let make = (~versions: array) => { let (actionCount, setActionCount) = React.useState(_ => 0) let onAction = _ => setActionCount(prev => prev > 1000000 ? 0 : prev + 1) let (compilerState, compilerDispatch) = useCompilerManager( + ~bundleBaseUrl, ~initialVersion?, ~initialModuleSystem?, ~initialLang, diff --git a/src/Playground.resi b/src/Playground.resi index 33288c00c..0c9fe47b4 100644 --- a/src/Playground.resi +++ b/src/Playground.resi @@ -1,2 +1,2 @@ @react.component -let make: (~versions: array) => React.element +let make: (~bundleBaseUrl: string, ~versions: array) => React.element diff --git a/src/Try.res b/src/Try.res index 374b029d6..88ab78268 100644 --- a/src/Try.res +++ b/src/Try.res @@ -1,4 +1,7 @@ -type props = {versions: array} +type props = { + bundleBaseUrl: string, + versions: array, +} let default = props => { let (isOverlayOpen, setOverlayOpen) = React.useState(() => false) @@ -19,7 +22,13 @@ let default = props => { }, ) - let playground = React.createElement(lazyPlayground, {versions: props.versions}) + let playground = React.createElement( + lazyPlayground, + { + bundleBaseUrl: props.bundleBaseUrl, + versions: props.versions, + }, + ) <> { } let getStaticProps: Next.GetStaticProps.t = async _ => { + let (bundleBaseUrl, versionsBaseUrl) = switch ( + Node.Process.Env.playgroundBundleEndpoint, + Node.Process.Env.nodeEnv, + ) { + | (Some(baseUrl), _) => (baseUrl, baseUrl) + | (None, "development") => { + // Use remote bundles in dev + let baseUrl = "https://cdn.rescript-lang.org" + (baseUrl, baseUrl) + } + | (None, _) => ( + // Use same-origin requests for the bundle + "", + // There is no version endpoint in the build phase + "https://cdn.rescript-lang.org", + ) + } let versions = { - let response = await fetch("https://cdn.rescript-lang.org/playground-bundles/versions.json") + let response = await fetch(versionsBaseUrl + "/playground-bundles/versions.json") let json = await WebAPI.Response.json(response) json ->JSON.Decode.array @@ -49,5 +75,10 @@ let getStaticProps: Next.GetStaticProps.t = async _ => { ->Array.map(json => json->JSON.Decode.string->Option.getOrThrow) } - {"props": {versions: versions}} + { + "props": { + bundleBaseUrl, + versions, + }, + } } diff --git a/src/Try.resi b/src/Try.resi index 5fec66502..9032885ea 100644 --- a/src/Try.resi +++ b/src/Try.resi @@ -1,3 +1,6 @@ -type props = {versions: array} +type props = { + bundleBaseUrl: string, + versions: array, +} let default: props => React.element let getStaticProps: Next.GetStaticProps.t diff --git a/src/bindings/Node.res b/src/bindings/Node.res index 9025de6a7..1f54aa73e 100644 --- a/src/bindings/Node.res +++ b/src/bindings/Node.res @@ -18,6 +18,8 @@ module Process = { @scope("process") external exit: int => unit = "exit" module Env = { @scope(("process", "env")) external nodeEnv: string = "NODE_ENV" + @scope(("process", "env")) + external playgroundBundleEndpoint: option = "PLAYGROUND_BUNDLE_ENDPOINT" } } diff --git a/src/common/CompilerManagerHook.res b/src/common/CompilerManagerHook.res index 6484eb8f1..f3fa40316 100644 --- a/src/common/CompilerManagerHook.res +++ b/src/common/CompilerManagerHook.res @@ -35,17 +35,13 @@ module LoadScript = { } module CdnMeta = { - let baseUrl = - Node.Process.Env.nodeEnv === "development" - ? "https://cdn.rescript-lang.org" - : "" + "/playground-bundles" + let getCompilerUrl = (baseUrl, version): string => + `${baseUrl}/${Semver.toString(version)}/compiler.js` - let getCompilerUrl = (version): string => `${baseUrl}/${Semver.toString(version)}/compiler.js` - - let getLibraryCmijUrl = (version, libraryName: string): string => + let getLibraryCmijUrl = (baseUrl, version, libraryName: string): string => `${baseUrl}/${Semver.toString(version)}/${libraryName}/cmij.js` - let getStdlibRuntimeUrl = (version, filename) => + let getStdlibRuntimeUrl = (baseUrl, version, filename) => `${baseUrl}/${Semver.toString(version)}/compiler-builtins/stdlib/${filename}` } @@ -104,11 +100,11 @@ let getOpenModules = (~apiVersion: Version.t, ~libraries: array): option We coupled the compiler / library loading to prevent ppl to try loading compiler / cmij files separately and cause all kinds of race conditions. */ -let attachCompilerAndLibraries = async (~version, ~libraries: array, ()): result< +let attachCompilerAndLibraries = async (~baseUrl, ~version, ~libraries: array, ()): result< unit, array, > => { - let compilerUrl = CdnMeta.getCompilerUrl(version) + let compilerUrl = CdnMeta.getCompilerUrl(baseUrl, version) // Useful for debugging our local build /* let compilerUrl = "/static/linked-bs-bundle.js"; */ @@ -117,7 +113,7 @@ let attachCompilerAndLibraries = async (~version, ~libraries: array, ()) | Error(_) => Error([`Could not load compiler from url ${compilerUrl}`]) | Ok(_) => let promises = Array.map(libraries, async lib => { - let cmijUrl = CdnMeta.getLibraryCmijUrl(version, lib) + let cmijUrl = CdnMeta.getLibraryCmijUrl(baseUrl, version, lib) switch await LoadScript.loadScriptPromise(cmijUrl) { | Error(_) => Error(`Could not load cmij from url ${cmijUrl}`) | r => r @@ -222,6 +218,7 @@ let defaultModuleSystem = "esmodule" // component to give feedback to the user that an action happened (useful in // cases where the output didn't visually change) let useCompilerManager = ( + ~bundleBaseUrl: string, ~initialVersion: option=?, ~initialModuleSystem=defaultModuleSystem, ~initialLang: Lang.t=Res, @@ -405,7 +402,12 @@ let useCompilerManager = ( // Latest version is already running on @rescript/react let libraries = getLibrariesForVersion(~version) - switch await attachCompilerAndLibraries(~version, ~libraries, ()) { + switch await attachCompilerAndLibraries( + ~baseUrl=bundleBaseUrl, + ~version, + ~libraries, + (), + ) { | Ok() => let instance = Compiler.make() let apiVersion = apiVersion->Version.fromString @@ -460,14 +462,16 @@ let useCompilerManager = ( | SwitchingCompiler(ready, version) => let libraries = getLibrariesForVersion(~version) - switch await attachCompilerAndLibraries(~version, ~libraries, ()) { + switch await attachCompilerAndLibraries(~baseUrl=bundleBaseUrl, ~version, ~libraries, ()) { | Ok() => // Make sure to remove the previous script from the DOM as well - LoadScript.removeScript(~src=CdnMeta.getCompilerUrl(ready.selected.id)) + LoadScript.removeScript(~src=CdnMeta.getCompilerUrl(bundleBaseUrl, ready.selected.id)) // We are removing the previous libraries, therefore we use ready.selected here Array.forEach(ready.selected.libraries, lib => - LoadScript.removeScript(~src=CdnMeta.getLibraryCmijUrl(ready.selected.id, lib)) + LoadScript.removeScript( + ~src=CdnMeta.getLibraryCmijUrl(bundleBaseUrl, ready.selected.id, lib), + ) ) let instance = Compiler.make() @@ -576,7 +580,7 @@ let useCompilerManager = ( } | version => version } - CdnMeta.getStdlibRuntimeUrl(compilerVersion, filename) + CdnMeta.getStdlibRuntimeUrl(bundleBaseUrl, compilerVersion, filename) }) entryPointExists diff --git a/src/common/CompilerManagerHook.resi b/src/common/CompilerManagerHook.resi index 113a5c7b7..bddb684dd 100644 --- a/src/common/CompilerManagerHook.resi +++ b/src/common/CompilerManagerHook.resi @@ -31,7 +31,7 @@ type ready = { } module CdnMeta: { - let getStdlibRuntimeUrl: (Semver.t, string) => string + let getStdlibRuntimeUrl: (string, Semver.t, string) => string } type state = @@ -53,6 +53,7 @@ type action = | RunCode let useCompilerManager: ( + ~bundleBaseUrl: string, ~initialVersion: Semver.t=?, ~initialModuleSystem: string=?, ~initialLang: Lang.t=?,