Uses Puppeteer to render a copy of the user's timetable on the server before taking a screenshot and sending it back to them.
# Configure. Comment out the `PAGE` line, as we'll set that in docker-compose.yml
$ cp .env.example .env
$ vim .env
# Change back to the repository root
$ cd ..
# Start all NUSMods Docker services in development mode, including the main web
# app and the standalone timetable page used by the export service
$ docker-compose up
Access NUSMods at http://localhost:8080. The export server can be used in the normal way – simply export a timetable as an image or PDF.
To update/rebuild:
- If only code is changed: nothing needs to be done – in development, code is automatically rebuilt and reloaded using
tsc --watch
andnodemon
. - If
package.json
dependencies are changed:docker-compose restart export
– the container is configured to runyarn install
on start. - If
Dockerfile.dev
is changed:docker-compose build export
,docker-compose restart export
# Install dependencies
# To skip Puppeteer installing Chromium, set PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
# See https://github.com/GoogleChrome/puppeteer/blob/v0.13.0/docs/api.md#environment-variables
$ yarn
# Configure - the defaults are sufficient for development, but for
# production these need to be updated
$ cp .env.example .env
$ vim .env
# Start the Webpack server for both the main web app and the standalone
# timetable page used by the export service
$ cd ../website
$ yarn start
$ yarn start:export
# Start export server - use "yarn devtools" if need to see the graphical browser with
# developer tools. Note that PDF export does not work in devtools mode.
$ cd ../export
$ yarn dev
- Dark mode
- Timetable orientation
- Hidden modules
- Custom coloring
- The user's client extracts the relevant slice of the Redux state necessary to render the timetable and serializes it into JSON
- The serialized state is added as query params to the 'Download as' link the user sees when they open the dropdown menu
- When the user clicks on the link, the browser makes a GET request to the chosen export endpoint
- The endpoint parses and validates the incoming data
- The export service uses the Puppeteer instance to create a new
Page
object - The page loads a special version of the app that only has the
<TimetableContent>
component, and injects the data into the Redux store - The screenshot or PDF is taken of the page, and sent back to the user
Both export API endpoints accept GET requests and take a data
query param that consists of JSON encoded data in the shape of ExportData
.
The endpoints use content-disposition
header to get the browser to download the file.
Download PDF of the timetable.
data
- JSON encoded timetable data
Download PNG image of the timetable.
data
- JSON encoded timetable datapixelRatio = 1
(Number: 1 to 3 inclusive) - the device pixel ratio as reported inwindow.devicePixelRatio
. This scales the entire image by that amount so it will appear correctly when downloaded to the user's device.
Returns the HTML content of the page that Puppeteer renders.
The export service can be deployed in 2 ways: with or without Docker. We are currently using the Docker approach in production.
See NUSMods deployment instructions.
In production the app runs behind pm2 in addition to nodemon, so the app will automatically restart when its files are changed or if the app crashes.
Export depends on build artifacts from website
. The deploy script for website
will automatically push updated versions of the artifacts to the correct folder, but staging needs to be updated manually. Use yarn rsync:export ../exports/dist-timetable
from the website
folder in staging to do this.
Here are the steps for deploying. We rsync everything over, including the node_modules
, so it is not necessary to run yarn
in the production folder.
# Update the files from the repo
$ git pull
# Install dependencies and build
$ yarn
$ yarn build
# Deploy the files to production - optionally add --dry-run to check which files are changed first
$ yarn deploy
# Starting the app, if the app is not already running
# Uses port 3300 for production and 3301 for staging
$ yarn start