From 49d378f3594d644752483b959b274836c8478dcb Mon Sep 17 00:00:00 2001 From: infoxicator Date: Thu, 10 Sep 2020 15:29:29 +0100 Subject: [PATCH 1/4] docs(recipes): update module deployment recipe --- docs/recipes/Deploying-Modules.md | 177 ++++++++++++++++-------------- docs/recipes/README.md | 2 +- 2 files changed, 95 insertions(+), 84 deletions(-) diff --git a/docs/recipes/Deploying-Modules.md b/docs/recipes/Deploying-Modules.md index 8c9a4089..f8168e79 100644 --- a/docs/recipes/Deploying-Modules.md +++ b/docs/recipes/Deploying-Modules.md @@ -5,83 +5,23 @@ # Deploying Modules ## 📖 Table of Contents +* [Deployment Overview](deployment-overview) +* [Creating a Module Map](#creating-a-module-map) +* [Update Module Map Script](#update-module-map-script) +* [Deploying to Vercel with GitHub Actions](#deploying-to-vercel-with-github-actions) -* [Deploying to Now with GitHub Actions](#deploying-to-now-with-github-actions) - * [Creating your Deploy Action](#creating-your-deploy-action) -* [Create and Update Your Module Map](#create-and-update-your-module-map) - * [Creating a Module Map in Now.sh](#creating-a-module-map-in-nowsh) - * [Create an Update Module Script](#create-an-update-module-script) - * [Update your Deploy Action to Update your Module Map](#update-your-deploy-action-to-update-your-module-map) +## Deployment Overview -## Deploying to Now with GitHub Actions +Deploying holocron modules consists on two steps: -[Now.sh](https://zeit.co/home) allows you to deploy statics such as your modules. We will accomplish this by using [GitHub Actions](https://github.com/features/actions). +1 Upload the contents of the `build` folder to your CDN of choice. +2. Update the [module map](../api/server/Module-Map-Schema.md) to point to the newly published static assets. -### Creating your Deploy Action +In the following example, we will use Vercel to deploy a holocron module and a manual script to deploy the module map. + +### Creating a Module Map -This deploy action uses Zeit's `now-cli` so you will need a create [token with Now](https://zeit.co/account/tokens). The below action runs whenever a release is created or a push to master occurs. You do not need to install or add `now-cli` to your `package.json` as the `now` command is available within GitHub actions, . - -```yml -name: Deploy - -on: - release: - types: [created] - push: - branches: - - master - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Use Node.js 12.x - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Cache NPM Dependencies - uses: actions/cache@v1 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - - name: Install Dependencies - run: npm install - env: - NODE_ENV: development - - name: Build Module - run: npm run build - env: - NODE_ENV: production - - name: 'Deploy' - run: now build --prod --confirm -t $NOW_TOKEN - env: - NOW_TOKEN: ${{ secrets.NOW_TOKEN }} -``` - -If you view the action running, during the `Deploy` step, you should see something like - -```bash -Run now build --prod --confirm -t $NOW_TOKEN -Now CLI 17.1.1 -- Setting up project -Linked to [YOUR NOW USERNAME]/[YOUR-REPO-NAME] (created .now and added it to .gitignore) -Inspect: https://zeit.co/[YOUR NOW USERNAME]/[YOUR-REPO-NAME]/ -- Building -- Completing -Production: https://[YOUR-REPO-NAME].now.sh -https://[YOUR-REPO-NAME]-[HASH].now.sh -``` - -## Create and Update Your Module Map - -You will now need to add the module you just deployed to your module map. - -### Creating a Module Map in Now.sh - -To create a module map in Now, you can create a module-map.json locally that looks something like this: +If you don't have an existing module map, you can create a `module-map.json` file locally that looks something like this: ```json { @@ -91,11 +31,17 @@ To create a module map in Now, you can create a module-map.json locally that loo } ``` -You can deploy this by running the [now](https://zeit.co/docs/now-cli#commands/now/basic-usage) command within the directory that you created the `module-map.json` in. You can now view it at the production URL that `now` prints out, you will need that URL for the following steps for the `moduleMapUrl` variable. +Then, you can upload it to Vercel using the [Vercel CLI](https://vercel.com/docs/cli#commands/overview/basic-usage) by running `vercel` within the directory that you created the `module-map.json` in. You can now view it at the production URL that `vercel` prints out, you will need that URL for the following steps for the `moduleMapUrl` variable. + +> Note: Your One App instance and all your module deployment jobs need to point at the same module map URL. One App requires that URL to be set in the [`HOLOCRON_MODULE_MAP_URL`](../api/server/Environment-Variables.md#holocron_module_map_url) environment variable. -### Create an Update Module Script +### Update Module Map Script -You can place this script wherever you would like. However, the following step expects it to be in `scripts/updateModuleMap.js`. If you put it in a different location, make sure you update it in the following step. +You can place this script wherever you would like. However, the following step expects it to be in the `scripts/updateModuleMap.js` folder of your module. If you put it in a different location, make sure you update it in the following step. + +> Note: The manual script presented below is just an example on how to update the module map by downloading your current module map, updating it to include the new deployed assets and re-uploading it, however, this approach doesn't handle concurrency. +There could be a case where two deployments running on different pipelines try to update the module map at the same time and a race condition might occur where the last deployment will override the contents of the first. If you want to avoid concurrency issues, we recommend to adopt +a "locking" mechanism as part of your CI to prevent the module map from being updated while another deployment is already in process. ```javascript const fs = require('fs-extra'); @@ -105,13 +51,13 @@ const { name, version } = require('../package.json'); // This is created during the build process within the deploy action const bundleIntegrity = require('../bundle.integrity.manifest.json'); -const moduleMapUrl = 'YOUR MODULE MAP URL'; // This is the module map URL you got in the previous step +const moduleMapUrl = 'YOUR MODULE MAP URL'; // This is the module map URL you got in the previous step i.e. https://example-module-map.vercel.app -const STATIC_ASSETS_URL = 'URL TO WHERE YOUR MODULE IS DEPLOYED'; // example 'https://my-module.now.sh' +const STATIC_ASSETS_URL = 'URL TO WHERE YOUR MODULE IS DEPLOYED'; // example 'https://my-module.vercel.app' const updateModuleMap = async () => { try { - const response = await fetch(moduleMapUrl); + const response = await fetch(moduleMapUrl); // download the current module map const moduleMapContent = await response.json(); const dir = 'module_map'; @@ -132,6 +78,8 @@ const updateModuleMap = async () => { }; await fs.ensureDir(dir); + // write the updated module map to a temporary folder + // so it can be re-uploaded by the deploy action await fs.writeFile( './module_map/module-map.json', JSON.stringify(moduleMapContent, null, 2) ); @@ -146,15 +94,78 @@ updateModuleMap().catch((err) => { }); ``` -### Update your Deploy Action to Update your Module Map +## Deploying to Vercel with GitHub Actions + +[Vercel](https://vercel.com/home) allows you to deploy statics assets such as your modules. We will accomplish this by using [GitHub Actions](https://github.com/features/actions). + +This deploy action uses the `vercel-cli` so you will need a create [token with Vercel](https://vercel.com/account/tokens) and then add a new variable called `VERCEL_TOKEN` to the `Secrets` section of your repository on Github. + +The below action runs whenever a release is created or a push to master occurs. You do not need to install or add `vercel-cli` to your `package.json` as the `vercel` command is available within GitHub actions. + +Create a new `.github/workflows/deploy.yml` file in the root folder of your module -At the bottom of your deploy action, you will want to add the following: ```yml - - name: 'Update Module Map' +name: Deploy + +on: + release: + types: [created] + push: + branches: + - master + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Use Node.js 12.x + uses: actions/setup-node@v1 + with: + node-version: '12.x' + - name: Cache NPM Dependencies + uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + - name: Install Dependencies + run: npm install + env: + NODE_ENV: development + - name: Build Module + run: npm run build + env: + NODE_ENV: production + - name: 'Deploy' + run: vercel build --prod --confirm -t $VERCEL_TOKEN --name [YOUR REPO NAME] + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + - name: 'Update Module Map' run: | node ./scripts/updateModuleMap.js - now module_map --prod --confirm -t $NOW_TOKEN --name [NAME OF YOUR MODULE MAP] + vercel module_map --prod --confirm -t $VERCEL_TOKEN --name [NAME OF YOUR MODULE MAP] env: - NOW_TOKEN: ${{ secrets.NOW_TOKEN }} + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} +``` +> Note: It is very important to set your `NODE_ENV=production` before running the `npm run build` command so the code is bundled and minified for production. + +The `deploy` stage on this action will publish the contents of the `build` folder to Vercel. The `Update Module Map` stage will run the script we created in `./scripts/updateModuleMap.js` and upload the updated module map placed in the temporary `module_map` folder to Vercel. + +If you view the action running, during the `Deploy` step, you should see something like: + +```bash +Run vercel build --prod --confirm -t $VERCEL_TOKEN --name [NAME OF YOUR MODULE] +Vercel CLI 20.1.0 +The "--name" option is deprecated (https://vercel.link/name-flag) +- Setting up project +Linked to [YOUR NOW USERNAME]/[YOUR REPO NAME](created .vercel and added it to .gitignore) +Inspect: https://vercel.com/[YOUR NOW USERNAME]/[YOUR REPO NAME] [1s] +- Queued +- Building +Production: https://[YOUR REPO NAME].vercel.app [6s] ``` + +You can inspect the contents of your module map deployed to Vercel to verify that it contains the links to the deployed assets of your modules. diff --git a/docs/recipes/README.md b/docs/recipes/README.md index a9349c12..83dea6d3 100644 --- a/docs/recipes/README.md +++ b/docs/recipes/README.md @@ -15,7 +15,7 @@ * [Running An Existing One App Instance Locally](./Running-Existing-App-Locally.md) 🔨 * [Running In Production](./Running-In-Production.md) 🔨 * [Monitoring One App](./Monitoring-One-App.md) 📌 -* [Deploying Modules](./Deploying-Modules.md) 🔨 +* [Deploying Modules](./Deploying-Modules.md) > 🔨 = This guide is a work-in-progress. > 📌 = This guide needs to be written. From 979161044e9baf0943222825667baf229e7e6c79 Mon Sep 17 00:00:00 2001 From: infoxicator Date: Thu, 10 Sep 2020 15:43:16 +0100 Subject: [PATCH 2/4] docs(recipes): module deployment typos --- docs/recipes/Deploying-Modules.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/recipes/Deploying-Modules.md b/docs/recipes/Deploying-Modules.md index f8168e79..5b36cc13 100644 --- a/docs/recipes/Deploying-Modules.md +++ b/docs/recipes/Deploying-Modules.md @@ -14,7 +14,7 @@ Deploying holocron modules consists on two steps: -1 Upload the contents of the `build` folder to your CDN of choice. +1. Upload the contents of the `build` folder to your CDN of choice. 2. Update the [module map](../api/server/Module-Map-Schema.md) to point to the newly published static assets. In the following example, we will use Vercel to deploy a holocron module and a manual script to deploy the module map. @@ -41,7 +41,7 @@ You can place this script wherever you would like. However, the following step e > Note: The manual script presented below is just an example on how to update the module map by downloading your current module map, updating it to include the new deployed assets and re-uploading it, however, this approach doesn't handle concurrency. There could be a case where two deployments running on different pipelines try to update the module map at the same time and a race condition might occur where the last deployment will override the contents of the first. If you want to avoid concurrency issues, we recommend to adopt -a "locking" mechanism as part of your CI to prevent the module map from being updated while another deployment is already in process. +a "locking" mechanism as part of your CI to prevent the module map from being updated while another deployment is already in progress. ```javascript const fs = require('fs-extra'); @@ -169,3 +169,5 @@ Production: https://[YOUR REPO NAME].vercel.app [6s] ``` You can inspect the contents of your module map deployed to Vercel to verify that it contains the links to the deployed assets of your modules. + +The running One App instance that points to your updated module map will automatically pull the newly deployed modules and update your application without the need for a server restart. From 2ef778a23bb14c442505d3fa502273f073ea6e55 Mon Sep 17 00:00:00 2001 From: infoxicator Date: Mon, 21 Sep 2020 14:42:37 +0100 Subject: [PATCH 3/4] docs(publishing): rename deploying modules to publishing --- ...loying-Modules.md => Publishing-Modules.md} | 18 ++++++++++-------- docs/recipes/README.md | 2 +- docs/recipes/Running-In-Production.md | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) rename docs/recipes/{Deploying-Modules.md => Publishing-Modules.md} (87%) diff --git a/docs/recipes/Deploying-Modules.md b/docs/recipes/Publishing-Modules.md similarity index 87% rename from docs/recipes/Deploying-Modules.md rename to docs/recipes/Publishing-Modules.md index 5b36cc13..80fe42c7 100644 --- a/docs/recipes/Deploying-Modules.md +++ b/docs/recipes/Publishing-Modules.md @@ -2,22 +2,22 @@ [👈 Return to Overview](./README.md) -# Deploying Modules +# Publishing Modules ## 📖 Table of Contents -* [Deployment Overview](deployment-overview) +* [Overview](overview) * [Creating a Module Map](#creating-a-module-map) * [Update Module Map Script](#update-module-map-script) * [Deploying to Vercel with GitHub Actions](#deploying-to-vercel-with-github-actions) -## Deployment Overview +## Overview -Deploying holocron modules consists on two steps: +Publishing Holocron modules consists on two steps: -1. Upload the contents of the `build` folder to your CDN of choice. -2. Update the [module map](../api/server/Module-Map-Schema.md) to point to the newly published static assets. +1. Upload the contents of the `build` folder to your CDN of choice. This publishes your module's static assets similar to when you release an npm dependency. +2. Update the [module map](../api/server/Module-Map-Schema.md) to point to the newly published static assets. This will tell One App to consume that published/released module version. -In the following example, we will use Vercel to deploy a holocron module and a manual script to deploy the module map. +In the following example, we will use Vercel to publish a holocron module and a manual script to deploy the module map. ### Creating a Module Map @@ -93,10 +93,12 @@ updateModuleMap().catch((err) => { console.log(err); }); ``` +>Note: Vercel only allows you to upload a single folder per project, this means that every holocron module will have its own URL and project name. Other CDNs like Cloudfront / Amazon S3 allow you to upload multiple folders. +>In that case, you can adjust the script above to include module name as the folder that contains the static assets for each holocron module. ## Deploying to Vercel with GitHub Actions -[Vercel](https://vercel.com/home) allows you to deploy statics assets such as your modules. We will accomplish this by using [GitHub Actions](https://github.com/features/actions). +[Vercel](https://vercel.com/home) allows you to publish statics assets such as your modules. We will accomplish this by using [GitHub Actions](https://github.com/features/actions). This deploy action uses the `vercel-cli` so you will need a create [token with Vercel](https://vercel.com/account/tokens) and then add a new variable called `VERCEL_TOKEN` to the `Secrets` section of your repository on Github. diff --git a/docs/recipes/README.md b/docs/recipes/README.md index 89b1f2af..e6888c05 100644 --- a/docs/recipes/README.md +++ b/docs/recipes/README.md @@ -15,7 +15,7 @@ * [Running A One App Instance Locally](./Running-One-App-Locally.md) * [Running In Production](./Running-In-Production.md) 🔨 * [Monitoring One App](./Monitoring-One-App.md) 📌 -* [Deploying Modules](./Deploying-Modules.md) +* [Publishing Modules](Publishing-Modules.md) > 🔨 = This guide is a work-in-progress. > 📌 = This guide needs to be written. diff --git a/docs/recipes/Running-In-Production.md b/docs/recipes/Running-In-Production.md index da0cd070..07c2f568 100644 --- a/docs/recipes/Running-In-Production.md +++ b/docs/recipes/Running-In-Production.md @@ -73,7 +73,7 @@ or the `.node.js` bundle when running on the server. One App has no opinion on where module bundles are deployed to, the only thing to keep in mind is that all the assets for a given module must be kept together when deployed, i.e. the file structure generated by [`one-app-bundler`] must not be modified. This is because the bundles rely on this -structure for knowing where to look for the lang packs. To see examples of how to deploy modules to certain hosting platforms, take a look at our documentation on [deploying modules](./Deploying-Modules.md). +structure for knowing where to look for the lang packs. To see examples of how to deploy modules to certain hosting platforms, take a look at our documentation on [publishing modules](Publishing-Modules.md). ## Building and Deploying a Holocron Module Map From 5423708a21bcb6aa916013d6411ceabb8654d77f Mon Sep 17 00:00:00 2001 From: infoxicator Date: Fri, 25 Sep 2020 13:40:03 +0100 Subject: [PATCH 4/4] docs(publishing): add CSP configuration --- docs/recipes/Publishing-Modules.md | 35 +++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/recipes/Publishing-Modules.md b/docs/recipes/Publishing-Modules.md index 80fe42c7..fec215c7 100644 --- a/docs/recipes/Publishing-Modules.md +++ b/docs/recipes/Publishing-Modules.md @@ -5,10 +5,11 @@ # Publishing Modules ## 📖 Table of Contents -* [Overview](overview) +* [Overview](#overview) * [Creating a Module Map](#creating-a-module-map) * [Update Module Map Script](#update-module-map-script) * [Deploying to Vercel with GitHub Actions](#deploying-to-vercel-with-github-actions) +* [Updating the Content Security Policy](#updating-the-content-security-policy) ## Overview @@ -173,3 +174,35 @@ Production: https://[YOUR REPO NAME].vercel.app [6s] You can inspect the contents of your module map deployed to Vercel to verify that it contains the links to the deployed assets of your modules. The running One App instance that points to your updated module map will automatically pull the newly deployed modules and update your application without the need for a server restart. + +## Updating the Content Security Policy + +One App enforces the [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) by default. You must add to the CSP the URL where your module's statics are loaded from, otherwise you will get a CSP violation and your modules will fail to load in Production. + +For example, to add Vercel to the Content Security Policy, add the `*.vercel.app` domain to the `connectSrc` and `scriptSrc` directives in your Root Module's `appConfig.js` file under the csp section: +```javascript +export default contentSecurityPolicyBuilder({ + directives: { + reportUri: process.env.ONE_CLIENT_CSP_REPORTING_URL, + defaultSrc: [ + "'self'", + ], + scriptSrc: [ + "'self'", + '*.vercel.app', + ], + imgSrc: [ + "'self'", + ], + styleSrc: [ + "'self'", + "'unsafe-inline'", + ], + connectSrc: [ + "'self'", + '*.vercel.app', + ], + }, +}); +``` +For more information on how to configure One App and the CSP please refer to this section: [App Configuration](../api/modules/App-Configuration.md#csp)