Practical Approach deploy nextJS with S3
Tags: aws, nextjs, devops, tutorial
Published: 2019-12-13 18:32:13

Recently I have a chance to deploy a react app using Next.js, which is part of the JS components. If you are new with nextjs, You can refer to this [link](https://nextjs.org/) to find out what it is. 

You can generate all assets such as css, js, etc automatically with Next.js and then, try to upload it to S3(If you are new with AWS S3, refer to this [link](https://docs.aws.amazon.com/AmazonS3/latest/gsg/CreatingABucket.html)) and serve it via CloudFront(If you are new with AWS Cloudfront, refer to this [link](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/GettingStarted.html)). With this S3+Cloudfront, we can fully serve our assets from AWS resources instead of using our service resources.

I started to do a research online and found a snippet at github that can be so much help for this project. Here is the link to the [snippet]
(https://gist.github.com/rbalicki2/30e8ee5fb5bc2018923a06c5ea5e3ea5)

So things that we need to prepare before doing this project are, have a proper IAM access (If you are new with AWS IAM, refer to this [link](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html)) for accessing S3 and CloudFront, and then create certificate for CloudFront/S3 since we're going to keep our assets inside those services.

On my first try, I follow the article blindly and found out that every time I deploy new services, all the assets that has been generated from nextjs will always have different hash than the assets which nextjs tried to access when we run the application. It's because we tried to generate the assets from application inside our CI/CD and then we try to build our application again inside Dockerfile, which will make it double in progress for generating assets in one application build process.

Then I realized the problem, I tried to update and modified the Dockerfile for accommodating our needs which we want to upload the assets shortly after we build the application.

After a couple of 'playing', This is my Dockerfile looks like:
```
FROM node:10.16.0 as build
ENV AWS_ACCESS_KEY_ID=give-your-AWS access KEY
ENV AWS_SECRET_ACCESS_KEY=give-your-AWS-secret-key
#it will made awscli we generated, can be access in node10
ENV PATH=/root/.local/bin:$PATH
RUN apt-get update && apt-get install -y python3-pip && pip3 install awscli --upgrade
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY ./package.json /app
# To handle 'not get uid/gid'
RUN npm config set unsafe-perm true
RUN npm install --silent
RUN npm install react-scripts@3.0.1 -g --silent
COPY ./app
RUN npm run build
RUN npm run export
#it can make us running in multiple environment
RUN mv out/_next .
RUN mv out _out
RUN mkdir -p out/builds/Our-BUild-Hash
RUN mv _out/* out/builds/Our-BUild-Hash
RUN rm -rf _out
RUN mv _next out/
RUN aws s3 cp ./out/_next s3://name-of-yours3bucket/test/_next --cache-control public --acl public-read --recursive
RUN aws s3 cp .//static s3://name-of-yours3bucket/test/static --cache-control public --acl public-read --recursive
RUN aws s3 cp ./out/builds s3://name-of-yours3bucket/test/builds --acl public-read --recursive
RUN aws s3 sync s3://name-of-yours3bucket/test/builds/$BITBUCKET_COMMIT s3://name-of-yours3bucket/test/current --delete --acl public-read

FROM node:10.16.0
COPY --from=0 /app /app
WORKDIR /app
EXPOSE 3000
CMD npm run start
```
There are a couple of new things here, in docker node 10.16.0. We can still install AWS CLI similar to the Ubuntu install process (In another article, I found almost a similar process but with node 9).

Other things we can do with multiple environments, is that we can make the process in the same bucket but on different folder.