大家好,我是山月,这是我最近新开的专栏:「前端部署系列」。包括 Docker、CICD 等内容,大纲图示如下:
大纲
示例代码开源,置于 Github 中,演示如何对真实项目进行部署上线。
「前端部署」系列正在更新: 6/20
本篇文章需要 OSS(Object Storage) 云服务服务,一个月几毛钱,可自行购买。我们可以把静态资源上传至 OSS,并对 OSS 提供 CDN 服务。
本篇文章还是以项目 cra-deploy1 示例,并将静态资源上传至 OSS 处理。
长按识别二维码查看原文 标题:cra-deploy
1. PUBLIC_PATH 与 webpack 的处理
假设将带有 hash 值的静态资源推至 CDN 中,此时静态资源的地址为: https://cdn.shanyue.tech
。而它即是我们将要在 webpack 中配置的 config.output.publicPath
。
module.exports = {
output: {
publicPath: 'https://cdn.shanyue.tech'
}
}
在 create-react-app
中,对 webpack config
做了进一步封装,阅读其源码,了解其 webpack.config.js
配置。
const publicUrlOrPath = getPublicUrlOrPath(
process.env.NODE_ENV === 'development',
require(resolveApp('package.json')).homepage,
process.env.PUBLIC_URL
)
const config = {
output: {
// webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path.
// We inferred the "public path" (such as / or /my-project) from homepage.
publicPath: paths.publicUrlOrPath,
},
}
可知「在 cra
中通过设置环境变量 PUBLIC_URL 即可配置 CDN 地址」。
export PUBLIC_URL=https://cdn.shanyue.tech
2. OSS 云服务之前的准备
2.1. AccessKey
- aliyun_access_key_id
- aliyun_access_key_secret
在将静态资源上传至云服务时,我们需要 AccessKey/AccessSecret 获得权限用以上传。可参考文档创建AccessKey2
长按识别二维码查看原文 标题:创建AccessKey
2.2. Bucket
Bucket
是 OSS 中的存储空间。「对于生产环境,可对每一个项目创建单独的 Bucket」,而在测试环境,多个项目可共用 Bucket。
在创建 Bucket 时,需要注意以下事项。
- 权限设置为公共读 (Public Read)
- 跨域配置 CORS (manifest.json 需要配置 cors)
- 记住 Endpoint,比如
oss-cn-beijing.aliyuncs.com
。将会在配置 PUBLIC_URL 中使用到
最终的 PUBLIC_URL 为 Bucket.Endpoint,比如本篇文章示例项目的 PUBLIC_URL 为 shanyue-cra.oss-cn-beijing.aliyuncs.com。
但是,你也可以配置 CNAME 记录并使用自己的域名。
在以下命令行及代码示例中,我们将 cra-deploy 项目的静态资源全部上传至 shanyue-cra
该 Bucket 中。
3. 将资源推送到 OSS: ossutil
在 OSS 上创建一个 Bucket,通过官方工具 ossutil3 将静态资源上传至 OSS。
长按识别二维码查看原文 标题:ossutil
- ossutil 安装4 长按识别二维码查看原文 标题:ossutil 安装
- ossutil 文档5 长按识别二维码查看原文 标题:ossutil 文档
在进行资源上传之前,需要通过 ossutil config
进行权限配置。
$ ossutil config -i $ACCESS_KEY_ID -k $ACCESS_KEY_SECRET -e $ENDPOINT
命令 ossutil cp
可将本地资源上传至 OSS。而缓存策略与前篇文章保持一致:
- 带有 hash 的资源一年长期缓存
- 非带 hash 的资源,需要配置 Cache-Control: no-cache,「避免浏览器默认为强缓存」
# 将资源上传到 OSS Bucket
$ ossutil cp -rf --meta Cache-Control:no-cache build oss://shanyue-cra/
# 将带有 hash 资源上传到 OSS Bucket,并且配置长期缓存
# 注意此时 build/static 上传了两遍 (可通过脚本进行优化)
$ ossutil cp -rf --meta Cache-Control:max-age=31536000 build/static oss://shanyue-cra/static
为求方便,可将两条命令维护到 npm scripts
中
{
scripts: {
'oss:cli': 'ossutil cp -rf --meta Cache-Control:no-cache build oss://shanyue-cra/ && ossutil cp -rf --meta Cache-Control:max-age=31536000 build/static oss://shanyue-cra/static'
}
}
4. 将资源推送到 OSS: npm scripts
另有一种方法,通过官方提供的 SDK: ali-oss6 可对资源进行精准控制:
长按识别二维码查看原文 标题:ali-oss
- 对每一条资源进行精准控制
- 仅仅上传变更的文件
- 使用 p-queue7 控制 N 个资源同时上传 长按识别二维码查看原文 标题:p-queue
{
scripts: {
'oss:script': 'node ./scripts/uploadOSS.js'
}
}
脚本略过不提。
PS: 上传 OSS 的配置文件位于 scripts/uploadOSS.js8 中,可通过它使用脚本控制静态资源上传。 长按识别二维码查看原文 标题:scripts/uploadOSS.js
5. Dockerfile 与环境变量
PS: 该 Dockerfile 配置位于 cra-deploy/oss.Dockerfile9 长按识别二维码查看原文 标题:cra-deploy/oss.Dockerfile
由于 Dockerfile
同代码一起进行管理,我们「不能将敏感信息写入 Dockerfile」。
故这里使用 ARG10 作为变量传入。而 ARG 可通过 docker build --build-arg
抑或 docker-compose
进行传入。
长按识别二维码查看原文 标题:ARG
代码语言:javascript复制FROM node:14-alpine as builder
ARG ACCESS_KEY_ID
ARG ACCESS_KEY_SECRET
ARG ENDPOINT
ENV PUBLIC_URL https://shanyue-cra.oss-cn-beijing.aliyuncs.com/
WORKDIR /code
# 为了更好的缓存,把它放在前边
RUN wget http://gosspublic.alicdn.com/ossutil/1.7.7/ossutil64 -O /usr/local/bin/ossutil
&& chmod 755 /usr/local/bin/ossutil
&& ossutil config -i $ACCESS_KEY_ID -k $ACCESS_KEY_SECRET -e $ENDPOINT
# 单独分离 package.json,是为了安装依赖可最大限度利用缓存
ADD package.json yarn.lock /code/
RUN yarn
ADD . /code
RUN npm run build && npm run oss:cli
# 选择更小体积的基础镜像
FROM nginx:alpine
ADD nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder code/build /usr/share/nginx/html
6. docker-compose 配置
PS: 该 compose 配置位于 cra-deploy/docker-compose.yaml11 长按识别二维码查看原文 标题:cra-deploy/docker-compose.yaml
在 docker-compose
配置文件中,通过 build.args
可对 Dockerfile
进行传参。
而 docker-compose.yaml
同样不允许出现敏感数据,此时「通过环境变量进行传参」。在 build.args
中,默认从同名环境变量中取值。
代码语言:javascript复制PS: 在本地可通过环境变量传值,那在 CI 中呢,在生产环境中呢?待以后 CI 篇进行揭晓。
version: "3"
services:
oss:
build:
context: .
dockerfile: oss.Dockerfile
args:
# 此处默认从环境变量中传参
- ACCESS_KEY_ID
- ACCESS_KEY_SECRET
- ENDPOINT=oss-cn-beijing.aliyuncs.com
ports:
- 8000:80
RUN 起来,成功!
代码语言:javascript复制$ docker-compose up --build oss
7. 免费的托管服务平台
经过几篇文章的持续优化,当我们使用对象存储服务之后,实际上在我们的镜像中仅仅只剩下几个文件。
index.html
robots.txt
favicon.ico
- 等
那我们可以再进一步,将所有静态资源都置于公共服务中吗?
可以,实际上 OSS/COS (对象存储服务) 也可以如此配置,但是较为繁琐,如 Rewrite、Redirect 规则等配置。
如果,你既没有个人服务器,也没有属于个人的域名,可将自己所做的前端网站置于以下免费的托管服务平台。
- Vercel
- Github Pages
- Netlify
8. 小结
通过本篇文章,我们已将静态资源部署至 CDN(近乎等同于 CDN),与大部分公司的生产环境一致。
但在测试环境中最好还是建议无需上传至 OSS,毕竟上传至 OSS 需要额外的时间,且对于测试环境无太大意义。
但实际上 OSS 在「上传及存储阶段」,还可以进一步优化,请看下一篇文章。
参考资料
[1]
cra-deploy:https://github.com/shfshanyue/cra-deploy
[2]
创建AccessKey:https://help.aliyun.com/document_detail/53045.html
[3]
ossutil:https://help.aliyun.com/document_detail/50452.html
[4]
ossutil 安装:https://help.aliyun.com/document_detail/120075.htm
[5]
ossutil 文档:https://help.aliyun.com/document_detail/50452.html
[6]
ali-oss:https://github.com/ali-sdk/ali-oss
[7]
p-queue:https://github.com/sindresorhus/p-queue
[8]
scripts/uploadOSS.js:https://github.com/shfshanyue/simple-deploy/blob/master/scripts/uploadOSS.js
[9]
cra-deploy/oss.Dockerfile:https://github.com/shfshanyue/cra-deploy/blob/master/oss.Dockerfile
[10]
ARG:https://docs.docker.com/engine/reference/builder/#arg
[11]
cra-deploy/docker-compose.yaml:https://github.com/shfshanyue/cra-deploy/blob/master/docker-compose.yaml