The new and shiny sites!
It's a server side rendered react thing. The idea is that the first pageload will be returned from the server and after that it acts like a single page app.
To run things:
yarn install
yarn build
yarn start
We can mentally divide Mosaico into two parts: the server code and the browser code. In production, both parts are required in order to run it as designed. However, as building the server dependent parts and restarting the thing continuously takes time and requires patience, it might be desired to run only the browser part when developing Mosaico. That is, if the development work does not concern the server itself. You can start the development server using Browsersync with yarn start-dev
.
yarn start-dev
will run two parallel jobs:
# Watches for purescript changes
spago build --watch
# Runs Browsersync and hot-reloads browser on ./dist and ./web changes
# On ./web changes, runs esbuild too
node ./run/hot-reload.js
Basically we are watching for purescript code changes and bundled javascript changes and syncing those to the browser.
When developing the server side bits, you need to restart the server after any changes with yarn start
or spago run
. Note that if your server side code requires also changes to the browser side of things, you need to build the static files with esbuild before running your server. This is what yarn build
does. This is a bit clumsy and again, a bit time consuming. The smoothest way of doing this currently is to run these commands (related Spago issue):
$ spago run
$ yarn start-dev
Under web/
we have index.html
and index.js
which can be thought of as templates that we load in the browser. This is the entry point for Mosaico react component. In fact, with these files alone, one could run a single page app version of Mosaico (yarn start-dev
). When the node server of Mosaico is involved, however, the server might want to write something to the files. Or more specifically, it will write to the esbuild built version of these files, located under dist/
. This is what yarn build
will do. Each yarn command is defined in package.json
under scripts
object. Let's look at what yarn build
does:
"scripts": {
"yarn build": "yarn run build-app && yarn run build-spa",
...
}
First we run spago build
(yarn run build-app
) which compiles our PureScript code into output/
. This is important, as we use the compiled PureScript in web/index.js
...
var Mosaico = require("../output/Mosaico/index.js").jsApp();
...
After that, we run node -e 'require(\"./run/build\").runBuild()
(yarn run build-spa
). Here, we build the file index.js
we have under web/
into a destination directory dist/assets/
. Esbuild does its thing: it finds every dependency it needs and places them into dist/assets/
. Unlike Parcel, esbuild will not handle html files automatically. In stead, in run/build.js
we manually copy web/index.html
and our static pages from static/*
into dist/
.
On static pages, the app initialization expects the selector "#app .mosaico--static-content" to match with the element containing the static content. This assumption isn't checked at build time.
To test pubsub frontpage updates, create a service account key to ksf-dev with Pub/Sub Editor and Pub/Sub Subscriber roles. Just Subscriber is not enough since it creates a new subscription at start up time.
export GOOGLE_APPLICATION_CREDENTIALS=
Where credentials is the JSON file downloaded from Google's cloud.
Mosaico uses the same code base for running a version of the site on the front end and the server. The differences this makes when developing for either are mostly papered over, but some things may still require a bit extra care.
Both environments use the same package.json
and spago.dhall
files
for defining dependencies. This means that the deps have some
libraries that are to be used only in one context, like pubsub and the
Affjax driver packages. This works as long as modules using those are
not included in both environments. If a server only module is
imported in both contextes it will fail with a bundler error.
Environment variables aren't by their nature available on the client
side. If you add new variables or modify their names, also update
runBuild
in run/build.mjs
. It pretty much does string
substitutions if the JS files have matches with those.
If you go "wait, process
is undefined in this context" (like in
Mosaico.js
) you are not wrong, but the build has a trick for it.
The ads and consent modals don't work in localhost. In order to get them working for local development, you need something like mitmproxy for connections:
- Install mitmproxy:
- OS X:
$ brew install mitmproxy
- Linux: open browser & go to https://mitmproxy.org/, click download and move binaries to somewhere in
$PATH
- OS X:
- Add
127.0.0.1 mosaico-hbl.staging.ksfmedia.fi
to /etc/hosts- Or
127.0.0.1 www.hbl.fi
if you want to fake prod
- Or
- Clear HSTS cache, otherwise you get HSTS errors:
- Firefox: Open history, find the stage/prod hbl site, right click -> forget about this site
- Chrome: navigate to
chrome://net-internals/#hsts
, enter the domain and click 'delete domain'
- Start mosaico (if not running already)
sudo mitmproxy -s scripts/cors.py --mode reverse:http://localhost:8000 -p 443
- Navigate to mosaico-hbl.staging.ksfmedia.fi and accept the self-signed certificate
Ensure that your phone and laptop are in the same wifi.
- Install mitmproxy (see above)
yarn build
- Find out your local ip address (eg. 192.168.1.126)
- Create a file called
proxy.pac
indist/
:- Content:
function FindProxyForURL(url, host) { return "SOCKS 192.168.1.126:8080"; }
- Replace the IP with your local ip
- Content:
yarn start
mitmproxy --mode socks5 -s scripts/proxy.py
- Configure your phone to use a automatic proxy script, and set that to
http://192.168.1.126:8080/proxy.pac
(replacing your IP again) - Open browser in your phone and go to
http://mitm.it
- Install certificate to your phone
http://192.168.1.126:8000
should be your local mosaico
Launch site as described in the Development sections. The tests may
fail with ads, consider using export DISABLE_ADS=1
before launching
Mosaico if that happens.
The test expects to get account data for testing from environment variables.
export TEST_USER=
export TEST_PASSWORD=
export ENTITLED_USER=
export ENTITLED_PASSWORD=
export LETTERA_URL=
spago -x test.dhall test
Since the js script does not work if inserted as inner html, therefore the script is in an external file. The js file has identical name as the html file and fetched at the same time as the html file and run after the DOM tree is built. When developing, yarn start-dev
will include the static files and hot-reload changes in the browser. Both html and js files for static pages are found in static/
directory.
You can install included git hooks with make hooks
Due to Google Tag Manager related reasons (see index.js), setTimeout is shimmed to replace setTimeout calls with 5 seconds to setTimeout with only 500 milliseconds.