Add the "Deploying projects" page

This commit is contained in:
Pete Gonzalez 2020-06-14 22:59:41 -07:00
Родитель 4c58569eb1
Коммит ec1ae2b8b3
1 изменённых файлов: 209 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,209 @@
---
layout: page
title: Deploying projects
navigation_source: docs_nav
---
Suppose that your monorepo includes a Node.js service that we want to deploy to a web server.
For example, let's say the Node.js service is a local Rush project called `app1`, and the repo is
organized as follows:
- **apps/app1**:
- depends on `ext-lib7` (from NPM) and `lib3` (a local project)
- dev dependencies on `ext-tool8` (from NPM) and `tool6` (a local project)
- **apps/app2**: depends on `lib3` and `lib4`
- **libraries/lib3**: depends on `lib5`
- **libraries/lib4**: no dependencies
- **libraries/lib5**: peer dependency on `ext-lib7`
- **tools/tool6**: no dependencies
One solution might be to run `rush install` and `rush build`, and then copy the entire monorepo to the server.
However, this could potentially include many extraneous files and NPM packages. Instead we would like to copy
only `app1` and its regular dependencies (`ext-lib7`, `lib3`, `lib5`). We do not want to include dev dependencies such
as `ext-tool8`.
The [rush deploy]({% link pages/commands/rush_deploy.md %}) command calculates this set of files and
copies them to a target folder, which you can then upload to your server.
## Configuring "rush deploy"
The `rush deploy` command reads its settings from a config file
[common/config/rush/deploy.json]({% link pages/configs/deploy_json.md %}). This config file is not created
by `rush init`. Instead, you create the file using [rush init-deploy]({% link pages/commands/rush_init-deploy.md %}).
Continuing our example, we can create the file using this command:
```shell
# Create common/config/rush/deploy.json and configure it to deploy "app1"
$ rush init-deploy --project app1
```
After the file **deploy.json** is created, open it in your editor and adjust the settings as appropriate. Then
commit this file to Git.
## Preparing a deployment
To copy the files to the deployment target folder, you would use these commands:
```shell
# Install dependencies
$ rush install
# Build the monorepo
$ rush build
# Copy app1 and its dependencies to the default target folder: common/deploy/
$ rush deploy
```
This will prepare a deployment by copying `app1` and its dependencies the target folder. The copied files will be
organized similarly to the monorepo's folder structure:
- **common/deploy/apps/app1/...**
- **common/deploy/common/temp/node_modules/ext-lib7/...**
- **common/deploy/libraries/lib3/...**
- **common/deploy/libraries/lib4/...**
You can test that the deployment worked correctly by executing `app1` from within the deployment target folder:
```shell
# Change to the app1 location under the target folder
$ cd common/deploy/apps/app1
# Invoke the package.json script that starts the web service
$ rushx start
```
If the project fails to run (but worked correctly from its original location **apps/app1**), then you many
need to tune the settings in **deploy.json**. Once you've confirmed that the project works correctly, the next step
is to upload the **common/deploy** subtree to your server machine.
## Handling links
The **common/deploy** subtree will have symbolic links created by `rush install`. For example, if you are using the
PNPM package manager, then **common/deploy/apps/app1/node_modules/ext-lib7** may be a symlink to a folder under the
**common/deploy/common/temp/node_modules/.pnpm/...** path. Correctly replicating these links can be problematic for
upload tools such as `tar` or `ftp`.
The **deploy.json** config file provides a setting `linkCreation` that offers choices for handling links:
- `"default"`: Create the links while copying the files; this is the default behavior. Use this setting if your
file copy tool can handle links correctly.
- `"script"`: A Node.js script called **create-links.js** will be written to the target folder. Use this setting
to create links on the server machine, after the files have been uploaded.
- `"none"`: Do nothing; some other tool may create the links later, based on the **deploy-metadata.json** file.
The **deploy-metadata.json** file is written to the deployment target folder and contains a full inventory of
links that need to be created. It might look something like this:
```js
{
"scenarioName": "deploy.json",
"mainProjectName": "app1",
"links": [
{
"kind": "folderLink",
"linkPath": "common/deploy/apps/app1/node_modules/ext-lib7",
"targetPath": "common/deploy/common/temp/node_modules/.pnpm/registry.npmjs.org/ext-lib7/1.0.0/node_modules/ext-lib7"
},
. . .
]
}
```
If you specify `"linkCreation": "script"` then `rush deploy` will create the **common/deploy** folder without
any links. After you have uploaded this folder to your server machine, you can then invoke the script
to create the links:
```shell
# Invoke this command on the server machine, after the files have been uploaded
$ node create-links.js create
```
## Including additional projects
Continuing our example, suppose that we want to include `app1` and `app2` together as a single deployment.
Since `app2` is not a dependency of `app1`, it will not be included automatically. We can consider `app1` to be
the "main project" (listed in `deploymentProjectNames`), and then declare `app2` as an "additional project".
The config file would look like this:
**common/config/rush/deploy.json**
```js
{
. . .
// The main project
"deploymentProjectNames": ["app1"],
. . .
"projectSettings": [
{
"projectName": "app1",
// When deploying "app1", include "app2". We need to add this explicitly because
// "app2" is not a dependency of "app1".
"additionalProjectsToInclude": [ "app2" ]
}
]
}
```
## Multiple deployments using the same config file
Continuing our example, suppose that instead we want `app1` and `app2` to be deployed separately to two different
web servers. If the settings are the same, we can simply add both of them to the `deploymentProjectNames` array,
like this:
**common/config/rush/deploy.json**
```js
. . .
"deploymentProjectNames": [ "app1", "app2" ],
. . .
```
When performing the deployment, the `--project` parameter selects which project to deploy. For example:
```shell
# Copy app1 and its dependencies to /mnt/deploy/app1
$ rush deploy --project app1 --target-folder /mnt/deploy/app1
# Copy app2 and its dependencies to /mnt/deploy/app2
$ rush deploy --project app2 --target-folder /mnt/deploy/app2
```
The `--target-folder` parameter copies the files to a custom location instead of the **common/deploy/** default folder.
## Multiple deployments using different config files
Continuing our example, suppose that `app2` deploys separately and it requires different settings from `app1`.
For example, suppose that we want `"linkCreation": "default"` for `app1`, but `"linkCreation": "script"` for `app2`.
We will create two config files:
- **common/config/rush/deploy.json** - the default scenario file, which we'll use for `app1`
- **common/config/rush/deploy-app2-example.json** -- the `app2-example` scenario, which we will use for `app2`
Both of these files can be created using `rush init-deploy`:
```shell
# Create common/config/rush/deploy.json
$ rush init-deploy --project app1
# Create common/config/rush/deploy-app2-example.json
$ rush init-deploy --project app2 --scenario app2-example
```
After editing **deploy-app2-example.json** to specify `"linkCreation": "script"`, we can now use the
`--scenario` parameter with `rush deploy`:
```shell
# Copy app1 and its dependencies to /mnt/deploy/app1
# Uses scenario file: common/config/rush/deploy.json
$ rush deploy --target-folder /mnt/deploy/app1
# Copy app2 and its dependencies to /mnt/deploy/app2
# Uses scenario file: common/config/rush/deploy-app2-example.json
$ rush deploy --target-folder /mnt/deploy/app2 --scenario app2-example
```
Note that the `--project` parameter is not needed with `rush deploy` because each config file has only one project
in its `"deploymentProjectNames"` array.