Before we get started, note that this post assumes that you have your CircleCI/Beanstalk integration working already. The reason for this is that setting that up itself is a very long-winded process. I may make a video about it some time, but in the mean time there is a very good medium post that explains how to set that up.
Also, a big special thanks to Rokt33r for the example repo that I shamelessly copied everything from :)
Why is this so different?
So, you may have seen examples of deploying node apps to Beanstalk and even got them working, but now you want to deploy a typescript app. You may be wondering how to ship your built files, since just shipping your source code isn't enough to get it running, unlike plain node.js.
So the key thing to remember is that you deploy your built assets, not your source code. That's actually true for even plain node apps, but it just so happens that in that case the build and the source is the same.
So, how do you do this? Well, assuming you've done the impossible hard bit of setting up AWS, Beanstalk, and CircleCI, the rest is actually quite easy.
Step 1: tsconfig.json
You should have that set up to compile your code. If you already have it, you don't need to change it, just take a note of what outDir
is as you'll need it. If you don't have it, or want to see an example, here is one.
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "dist",
"sourceMap": true,
"baseUrl": ".",
"paths": {
"*": [
"node_modules/*",
"src/types/*"
]
}
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
]
}
Step 2: package.json
You should already have start
and build
scripts, but if not, here is an example:
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
},
build
is the command used to build your software; in this case it's tsc
to compile the typescript down to javascript.
start
is how you start your software, obviously this depends on your app but it's usually something like node dist/index.js
. Note that you're pointing to your compiled js code. The location may not be dist
; but it's whatever you have set as outDir
in tsconfig.json
.
Step 3: dist
step
If you've seen the UI for Elastic Beanstalk for AWS, you basically deploy apps to it by uploading .zip
files. If you use the command line (eb deploy
), it does that for you. What we essentially want to do is to build your dist
ribution .zip
file to upload. How? Essentially by zipping your dist
directory.
Make a file called scripts/dist.sh
, and put the following code in:
# If the directory, `dist`, doesn't exist, create `dist`
stat dist || mkdir dist
# Archive artifacts
zip dist/$npm_package_name.zip -r dist package.json package-lock.json
If you're not using dist
as the directory name for your build (remember the outDir
from earlier), you need to change it above.
This will basically build your zip for you!
You can test it out manually:
errietta@Moltres [4] (git)-[master] ~/hyperbudget-backend % bash scripts/dist.sh
File: 'dist'
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 801h/2049d Inode: 16393011 Links: 6
Access: (0775/drwxrwxr-x) Uid: ( 1000/errietta) Gid: ( 1000/errietta)
Access: 2018-06-16 11:41:27.842696048 +0100
Modify: 2018-05-24 19:59:55.741014000 +0100
Change: 2018-05-24 19:59:55.741014000 +0100
Birth: -
adding: dist/ (stored 0%)
adding: dist/app.js (deflated 70%)
....
adding: dist/index.js (deflated 39%)
adding: dist/index.js.map (deflated 58%)
adding: package.json (deflated 65%)
adding: package-lock.json (deflated 77%)
errietta@Moltres [4] (git)-[master] ~/hyperbudget-backend %
This will actually generate dist/.zip
- that's because when you run it manually, $npm_package_name
is not set. Feel free to look at that zip file and verify that all your built javascript is in there. If it's correct, delete the file, we'll tell npm to generate it instead in the next step!
Step 4: Set up the npm dist script
Really simple, just add another script to your package.json
. For example:
"scripts": {
"build": "tsc",
"dist": "sh ./scripts/dist.sh",
"start": "node dist/index.js"
},
Now you can run your dist
step by doing npm run dist
! If you run that, you will now have a zip file in your dist
folder that is actually named after your app, and you can open it and again verify that you have all your compiled javascript there.
Step 5: Amend CircleCI configuration
Now we need to tell CircleCI to run npm run build
and npm run dist
. This will depend on your configuration, but basically edit .circleci/config.yml
and make sure that npm run build
and npm run dist
is ran before eb deploy
. For example, I have the following:
- deploy:
name: Deploy to Elastic Beanstalk
command: |
npm install && npm run build && npm run dist && eb deploy --staged MyApp-env
This will install all my dependencies, compile my app down to javascript, run npm run dist
to generate the zip file, and deploy to Beanstalk. Hang on, though, how do we tell Beanstalk to use that zip file?
Step 6: Beanstalk configuration
Create or amend your .elasticbeanstalk/config.yml
file. In there, you need to add the following:
deploy:
artifact: dist/YOUR-APP-NAME.zip
The name of the zip should be the same as your npm package name if you have set up the dist.sh
script to use $npm_package_name
. You can always manually run npm run dist
and then see the name of the file it generates.
If you don't have an elasticbeanstalk/config.yml
file, here is a simple one that works for me:
branch-defaults:
master:
environment: MyApp-env
staging:
environment: MyApp-env
dev:
environment: MyApp-env
global:
application_name: my-app
default_platform: 64bit Amazon Linux 2017.03 v4.5 running Node 8.10
default_region: eu-central-1
deploy:
artifact: dist/my-app.zip
You should change your branch names and environnment names to match your deployed branches and your Beanstalk environment names respectively, and you can change the region and platform if you ned to. The important thing is for the artifact
to be correct, this will tell beanstalk to deploy your zip file
That's it!
If you set up all this correctly, circleci should now be deploying your zip file to beanstalk. You can check the CircleCI build information and verify that it runs tsc
, zips up your files, and deploys to Beanstalk. Here's what mine looks like for comparison:
#!/bin/bash -eo pipefail
npm install && npm run build && npm run dist && eb deploy --staged MyApp-env
> ursa@0.9.4 install /home/circleci/app/node_modules/ursa
> node-gyp rebuild
make: Entering directory '/home/circleci/app/node_modules/ursa/build'
CXX(target) Release/obj.target/ursaNative/src/ursaNative.o
SOLINK_MODULE(target) Release/obj.target/ursaNative.node
COPY Release/ursaNative.node
make: Leaving directory '/home/circleci/app/node_modules/ursa/build'
added 232 packages in 11.433s
> my-app@1.0.0 build /home/circleci/app
> tsc
> my-app@1.0.0 dist /home/circleci/app
> sh ./scripts/dist.sh
File: ‘dist’
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 100016h/1048598d Inode: 7272 Links: 4
Access: (0755/drwxr-xr-x) Uid: ( 3434/circleci) Gid: ( 3434/circleci)
Access: 2018-06-14 13:37:17.348967660 +0000
Modify: 2018-06-14 13:37:17.376967104 +0000
Change: 2018-06-14 13:37:17.376967104 +0000
Birth: -
adding: dist/ (stored 0%)
adding: dist/App.js (deflated 51%)
adding: dist/index.js (deflated 39%)
adding: dist/script/ (stored 0%)
adding: dist/App.js.map (deflated 64%)
adding: package.json (deflated 56%)
adding: package-lock.json (deflated 77%)
Uploading my-app/app-******.zip to S3. This may take a while.
Upload Complete.
INFO: Environment update is starting.
INFO: Deploying new version to instance(s).
INFO: New application version was deployed to running EC2 instances.
INFO: Environment update completed successfully.
You can see that it ran npm install
, tsc
, and then my ./scripts/dist.sh
which zipped all my built files, and then successfully deployed it to EC2.
I hope this helps someone else, thanks for reading :)
Top comments (0)