Skip to content

Commit 0758325

Browse files
Update to 0.15.0; use ES Module Shims (#275)
* Update changelog for last release * Update purescript deps for 0.15.2; drop cst dep * Upgrade to latest pkg set; install entire set * Get server code to compile * Use ES Modules Shims for iframe shims * Add serve:production script * Add instructions for adding shims to import map * Doc how to calc integrity hash * Fix infinite invocation of `main` call * Update base to production; fail CI if not that * Update readme instructions
1 parent 6e0a98a commit 0758325

20 files changed

+201
-425
lines changed

.github/workflows/ci.yml

+6
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ jobs:
7272
npm run build
7373
npm run test
7474
npm run build:production
75+
if [ "/output/ignored/" != "$(cat public/frame.html | grep '<base' | sed -E 's/ +<base href="([^"]+)">/\1/;')" ]; then
76+
echo "client/public/frame.html's 'base' element refers to the wrong path"
77+
echo "Run 'npm run base:production' in the 'client' dir, and push the update as a commit"
78+
echo "CI will fail until then"
79+
exit 1
80+
fi
7581
7682
- name: Build client assets
7783
if: github.event_name == 'release'

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ Notable changes to this project are documented in this file. The format is based
44

55
## [Unreleased]
66

7+
Breaking changes:
8+
9+
New features:
10+
11+
Bugfixes:
12+
13+
Other improvements:
14+
15+
## [v2022-02-25.1](https://github.com/purescript/trypurescript/releases/tag/v2022-02-25.1)
16+
717
Breaking changes:
818
- Update compiler to v0.14.7 (#271 by @JordanMartinez)
919

README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,15 @@ ln -s "$PWD/output" "$PWD/../client/public/js/output"
9696
cd client
9797
npm install
9898

99-
# Use `build:dev` if you are using a local Try PureScript server, e.g. you
100-
# followed the instructions in step 1.
99+
# Use `build:dev` and `base:dev` if you are using a local Try PureScript server,
100+
# e.g. you followed the instructions in step 1.
101101
#
102-
# Use `build:production` if you would like to test the client against the production
103-
# Try PureScript server.
102+
# Use `build:production` and `base:production` if you would like
103+
# to test the client against the production Try PureScript server.
104104
npm run build:(dev|production)
105+
npm run base:(dev|production)
105106

106-
cd public
107-
npx http-server # Try PureScript is now available on localhost:8080
107+
npm run serve # Try PureScript is now available on localhost:8080
108108
```
109109

110110
### 4. Choosing a Tag

RELEASE.md

+18
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,21 @@ Update the package set by doing the following:
3939
```
4040
$ spago ls packages | cut -f 1 -d ' ' | xargs spago install
4141
```
42+
43+
4. If any packages need NPM dependencies, you can try adding their shims to the import map in `client/public/frame.html`
44+
- Open up the `generator.jspm.io` URL in the comment
45+
- Use the 'Add Dependency' search bar to find the NPM dependency
46+
- If it exists but doesn't exist in that CDN, you can try another one or [open an issue on `jspm/project`](https://github.com/jspm/project#issue-queue-for-the-jspm-cdn)
47+
- Update the version to the one you need once added
48+
- If needed, include other files from that dependency
49+
- Copy and paste the content into the `client/public/frame.html` file
50+
- Ensure `es-module-shims` has version `1.5.5` or greater.
51+
52+
5. If `es-module-shims` releases a new version, you can calculate its SHA-384 via
53+
54+
```console
55+
$ ESM_VERSION=1.5.5
56+
$ curl -L -o es-module-shims.js "https://ga.jspm.io/npm:es-module-shims@$ESM_VERSION/dist/es-module-shims.js"
57+
$ echo "sha384-$(openssl dgst -sha384 -binary es-module-shims.js | openssl base64 -A)"
58+
$ rm es-module-shims.js
59+
```

client/config/dev/Try.Config.purs

-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ module Try.Config where
22

33
import Prelude
44

5-
loaderUrl :: String
6-
loaderUrl = "js/output"
7-
85
compileUrl :: String
96
compileUrl = "http://localhost:8081"
107

client/config/prod/Try.Config.purs

-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ module Try.Config where
22

33
import Prelude
44

5-
loaderUrl :: String
6-
loaderUrl = "https://compile.purescript.org/output"
7-
85
compileUrl :: String
96
compileUrl = "https://compile.purescript.org"
107

client/package.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
"private": true,
44
"scripts": {
55
"clean": "rimraf output",
6+
"base:dev": "node setBase.mjs \"dev\"",
7+
"base:production": "node setBase.mjs \"prod\"",
68
"test": "spago test --path config/dev/Try.Config.purs",
79
"build": "spago build --path config/dev/Try.Config.purs",
810
"build:dev": "spago bundle-app --path config/dev/Try.Config.purs --to public/js/index.js",
9-
"build:production": "spago bundle-app --path config/prod/Try.Config.purs --purs-args '--censor-lib --strict' --to public/js/index.js"
11+
"build:production": "spago bundle-app --path config/prod/Try.Config.purs --purs-args '--censor-lib --strict' --to public/js/index.js",
12+
"serve": "http-server public/ -o / --cors=\"Access-Control-Allow-Origin: *\" -c-1",
13+
"serve:dev": "npm run build:dev && npm run base:dev && npm run serve",
14+
"serve:production": "npm run build:production && npm run base:production && npm run serve"
1015
},
1116
"devDependencies": {
17+
"http-server": "^14.1.0",
1218
"purescript": "^0.13.6",
1319
"purescript-psa": "^0.7.3",
1420
"rimraf": "^2.5.4",

client/public/frame.html

+42-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,49 @@
55
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
66
<meta content="utf-8" http-equiv="encoding">
77
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8-
<script src="js/frame.js"></script>
8+
<!-- Do not edit the base element's 'href' manually. Use the 'base:dev' or 'base:production' script -->
9+
<base href="/output/ignored/">
10+
<script>
11+
window.esmsInitOptions = {
12+
// -- Hooks --
13+
// Module load error
14+
onerror: (e) => {
15+
console.log("Error while loading module: ");
16+
console.log(e);
17+
throw e;
18+
},
19+
};
20+
</script>
21+
<!--
22+
JSPM Generator Import Map
23+
Edit URL: https://generator.jspm.io/#Y2NnYGCzD80rySzJSU1hSMpM183MK0lNTy1yMNQz0zM1ZEhJTc7MTczRyyp2MDTQM9YzZChKTUwu0U3Jz3UwNNMzxCqiX5xaVJZaBJGAKystzUxxsACaYQQAoBlP83cA
24+
-->
25+
<script type="importmap">
26+
{
27+
"imports": {
28+
"big-integer": "https://ga.jspm.io/npm:[email protected]/BigInteger.js",
29+
"decimal.js": "https://ga.jspm.io/npm:[email protected]/decimal.js",
30+
"react": "https://ga.jspm.io/npm:[email protected]/index.js",
31+
"react-dom": "https://ga.jspm.io/npm:[email protected]/index.js",
32+
"react-dom/server": "https://ga.jspm.io/npm:[email protected]/server.browser.js",
33+
"uuid": "https://ga.jspm.io/npm:[email protected]/dist/esm-browser/index.js"
34+
},
35+
"scopes": {
36+
"https://ga.jspm.io/": {
37+
"object-assign": "https://ga.jspm.io/npm:[email protected]/index.js",
38+
"react": "https://ga.jspm.io/npm:[email protected]/index.js",
39+
"scheduler": "https://ga.jspm.io/npm:[email protected]/index.js"
40+
}
41+
}
42+
}
43+
</script>
44+
45+
<!-- ES Module Shims: Import maps polyfill for modules browsers without import maps support (all except Chrome 89+) -->
46+
<script async src="https://ga.jspm.io/npm:[email protected]/dist/es-module-shims.js" integrity="sha384-Zt+0efULC2q2dftjz0uNzXeTpPVuSLLekXQv9HoRuigkAyLPaUFvPVpYYhu2Xc/t" crossorigin="anonymous"></script>
47+
48+
<script src="/js/frame.js"></script>
949
</head>
1050
<body>
11-
<main id="main"></main>
51+
<main id="main"></main>
1252
</body>
1353
</html>

client/public/js/frame.js

+8-32
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,18 @@
11
(function() {
2-
function evalSources(sources) {
3-
var modules = {};
4-
function dirname(str) {
5-
var ix = str.lastIndexOf("/");
6-
return ix < 0 ? "" : str.slice(0, ix);
7-
}
8-
function resolvePath(a, b) {
9-
if (b[0] === "." && b[1] === "/") {
10-
return dirname(a) + b.slice(1);
11-
}
12-
if (b[0] === "." && b[1] === "." && b[2] === "/") {
13-
return dirname(dirname(a)) + b.slice(2);
14-
}
15-
return b;
16-
}
17-
return function load(name) {
18-
if (modules[name]) {
19-
return modules[name].exports;
20-
}
21-
function require(path) {
22-
return load(resolvePath(name, path));
23-
}
24-
var module = modules[name] = { exports: {} };
25-
new Function("module", "exports", "require", sources[name])(module, module.exports, require);
26-
return module.exports;
27-
};
28-
}
29-
302
var parent;
313

324
document.addEventListener("DOMContentLoaded", function() {
335
window.addEventListener("message", function(event) {
346
parent = event.source;
357
parent.postMessage("trypurescript", "*");
36-
var file = evalSources(event.data)("<file>");
37-
if (file.main && typeof file.main === "function") {
38-
file.main();
39-
}
8+
const code = `
9+
${event.data.code}
10+
main();
11+
`;
12+
const scriptEl = document.createElement("script");
13+
scriptEl.type = "module";
14+
scriptEl.appendChild(document.createTextNode(code));
15+
document.body.appendChild(scriptEl);
4016
}, { once: true });
4117
}, { once: true });
4218

client/setBase.mjs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env node
2+
3+
import path from "path";
4+
import fs from "fs";
5+
import process from "process";
6+
7+
const filePath = path.join("public", "frame.html");
8+
9+
// PureScript generates JS with the following import lines:
10+
// `import * as Data_Foo from "../Data.Foo/index.js"
11+
// To remap `../Data.Foo/index.js` to `output/Data.Foo/index.js`
12+
// we append `/ignored/`.
13+
//
14+
// This: `/output/ignored/../Data.Foo/index.js`
15+
// becomes: `/output/Data.Foo/index.js`
16+
const prodPath = "/output/ignored/"
17+
const devPath = "/js/output/ignored/"
18+
19+
const environment = process.argv[2] || "dev";
20+
const baseHref = environment === "prod" ? prodPath : devPath;
21+
22+
const frameHtml = fs.readFileSync(filePath, "utf-8");
23+
const newHtml = frameHtml
24+
.split("\n")
25+
.map((line) => line.replace(/^( *<base href=")[^"]*(".+)$/, `$1${baseHref}$2`))
26+
.join("\n");
27+
28+
fs.writeFileSync(filePath, newHtml);

client/src/Try/Container.purs

+8-20
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import Effect.Aff (Aff, makeAff)
1616
import Effect.Aff as Aff
1717
import Effect.Class.Console (error)
1818
import Effect.Uncurried (EffectFn3, runEffectFn3)
19-
import Foreign.Object (Object)
20-
import Foreign.Object as Object
2119
import Halogen as H
2220
import Halogen.HTML as HH
2321
import Halogen.HTML.Events as HE
@@ -29,10 +27,8 @@ import Try.Editor (MarkerType(..), toStringMarkerType)
2927
import Try.Editor as Editor
3028
import Try.Gist (getGistById, tryLoadFileFromGist)
3129
import Try.GitHub (getRawGitHubFile)
32-
import Try.Loader (Loader, makeLoader, runLoader)
3330
import Try.QueryString (getQueryStringMaybe)
3431
import Try.Session (createSessionIdIfNecessary, storeSession, tryRetrieveSession)
35-
import Try.Types (JS(..))
3632
import Web.HTML (window)
3733
import Web.HTML.Window (alert)
3834

@@ -83,12 +79,9 @@ data Action
8379
_editor :: SProxy "editor"
8480
_editor = SProxy
8581

86-
loader :: Loader
87-
loader = makeLoader Config.loaderUrl
88-
8982
type LoadCb = Effect Unit
9083
type FailCb = Effect Unit
91-
foreign import setupIFrame :: EffectFn3 (Object JS) LoadCb FailCb Unit
84+
foreign import setupIFrame :: EffectFn3 { code :: String } LoadCb FailCb Unit
9285
foreign import teardownIFrame :: Effect Unit
9386

9487
component :: forall q i o. H.Component HH.HTML q i o Aff
@@ -189,22 +182,17 @@ component = H.mkComponent
189182
if settings.showJs then
190183
H.liftEffect teardownIFrame
191184
else do
192-
eitherSources <- H.liftAff $ runExceptT $ runLoader loader (JS js)
193185
for_ warnings \warnings_ -> do
194186
let anns = Array.mapMaybe (toAnnotation MarkerWarning) warnings_
195187
_ <- H.query _editor unit $ H.tell $ Editor.SetAnnotations anns
196188
pure unit
197-
case eitherSources of
198-
Right sources -> do
199-
let eventData = Object.insert "<file>" (JS js) sources
200-
H.liftAff $ makeAff \f -> do
201-
runEffectFn3 setupIFrame eventData (f (Right unit)) (f (Left $ Aff.error "Could not load iframe"))
202-
mempty
203-
H.modify_ _ { compiled = Just (Right res) }
204-
Left err -> do
205-
H.liftEffect teardownIFrame
206-
H.liftEffect $ error err
207-
H.modify_ _ { compiled = Just (Left err) }
189+
let
190+
eventData = { code: js }
191+
H.liftEffect teardownIFrame
192+
H.liftAff $ makeAff \f -> do
193+
runEffectFn3 setupIFrame eventData (f (Right unit)) (f (Left $ Aff.error "Could not load iframe"))
194+
mempty
195+
H.modify_ _ { compiled = Just (Right res) }
208196

209197
HandleEditor (Editor.TextChanged text) -> do
210198
_ <- H.fork $ handleAction $ Cache text

0 commit comments

Comments
 (0)