从自己写js第一天到今天,js构建模式发生了太大的变化,从自己的第一个js项目: https://loveyu.org/2429.html 到现在这些看懂都困难的js项目,差不多过去了十多年了吧。
举个例子,看看今天的项目构建最终方案:
# 打包要使用的镜像
FROM harbor.example.net/base-nvm-of-frontend:1.0.0 AS build-src
#建立工作目录
RUN mkdir -p /data \
&& mkdir -p /data/m \
&& mkdir -p /data/pc
WORKDIR /data
# 安装git过程中需要进行交互,使用-y命令自动执行交互安装
# 执行apt-get update的时候,会下载一些临时文件到该目录,所以删除
RUN apt-get update \
&& apt-get install -y git \
&& rm -rf /var/lib/apt/lists/*
COPY ./m/package.json ./m/package.json
COPY ./pc/package.json ./pc/package.json
COPY ./m/package-lock.json ./m/package-lock.json
COPY ./pc/package-lock.json ./pc/package-lock.json
# 为了执行nvm命令,执行 /root/.bashrc脚本
RUN source /root/.bashrc \
&& nvm install "v8.9.4" \
&& nvm use "v8.9.4" \
&& npm install example-npm -g --registry=http://npm.example.net/
RUN cd /data/pc \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& npm install --registry=http://npm.example.net/
RUN cd /data/m \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& npm install --registry=http://npm.example.net/
# ##################### 缓存到此结束 ########################################
# m版制文件并开始打包
ARG BUILD_ARG
ARG ENV_ARG
COPY ./docker/ /data/docker
COPY ./m/ /data/m
# 处理zzc-design-mobile引用文件的大小写问题
RUN cd /data/m \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& echo "当前构建: m_${ENV_ARG}" \
&& cp /data/docker/${ENV_ARG}-host.json /data/m/local_server/host/.host.json \
&& echo "开始打包" \
&& npm run ${BUILD_ARG}
# pc版制文件并开始打包
COPY ./pc/ /data/pc
RUN cd /data/pc \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& echo "当前构建: pc_${ENV_ARG}" \
&& echo "开始打包" \
&& npm run ${BUILD_ARG}
# 生产要使用的镜像
FROM harbor.example.net/base-nginx:1.18.0 AS build-image
COPY --from=build-src /data/m/dist /data/example/m/dist/
COPY --from=build-src /data/pc/dist /data/example/pc/dist/
COPY ./docker/nginx.conf /etc/nginx/nginx.conf
EXPOSE 8888
FROM harbor.example.net/base-nvm-of-frontend:1.0.0 AS build-src
#建立工作目录
RUN mkdir -p /data \
&& mkdir -p /data/m \
&& mkdir -p /data/pc
WORKDIR /data
# 安装git过程中需要进行交互,使用-y命令自动执行交互安装
# 执行apt-get update的时候,会下载一些临时文件到该目录,所以删除
RUN apt-get update \
&& apt-get install -y git \
&& rm -rf /var/lib/apt/lists/*
COPY ./m/package.json ./m/package.json
COPY ./pc/package.json ./pc/package.json
COPY ./m/package-lock.json ./m/package-lock.json
COPY ./pc/package-lock.json ./pc/package-lock.json
# 为了执行nvm命令,执行 /root/.bashrc脚本
RUN source /root/.bashrc \
&& nvm install "v8.9.4" \
&& nvm use "v8.9.4" \
&& npm install example-npm -g --registry=http://npm.example.net/
RUN cd /data/pc \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& npm install --registry=http://npm.example.net/
RUN cd /data/m \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& npm install --registry=http://npm.example.net/
# ##################### 缓存到此结束 ########################################
# m版制文件并开始打包
ARG BUILD_ARG
ARG ENV_ARG
COPY ./docker/ /data/docker
COPY ./m/ /data/m
# 处理zzc-design-mobile引用文件的大小写问题
RUN cd /data/m \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& echo "当前构建: m_${ENV_ARG}" \
&& cp /data/docker/${ENV_ARG}-host.json /data/m/local_server/host/.host.json \
&& echo "开始打包" \
&& npm run ${BUILD_ARG}
# pc版制文件并开始打包
COPY ./pc/ /data/pc
RUN cd /data/pc \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& echo "当前构建: pc_${ENV_ARG}" \
&& echo "开始打包" \
&& npm run ${BUILD_ARG}
# 生产要使用的镜像
FROM harbor.example.net/base-nginx:1.18.0 AS build-image
COPY --from=build-src /data/m/dist /data/example/m/dist/
COPY --from=build-src /data/pc/dist /data/example/pc/dist/
COPY ./docker/nginx.conf /etc/nginx/nginx.conf
EXPOSE 8888
整体构建过程看起来还是蛮简单的,无非就是分为2个大部分,打包和复制打包结果,但是实际涉及到缓存复用等一大堆麻烦的问题,隔壁的同事整整折腾了2天才搞定。
很关键的一点,看harbor.example.net/base-nvm-of-frontend:1.0.0,为什么基础镜像是一个看起来像专项定制,实际上它就是专项定制。毕竟你要知道npm安装这个事情是存在一定概率的,而且也要知道node-sass这类安装及其困难,一不小心就安装失败,进程修改代码5分钟,安装编译5小时。
于是整体镜像化还是很重要的,所以就有了定制化的底包。
FROM harbor.example.net/base-nvm:0.38.0
USER root
#建立工作目录
RUN mkdir -p /data \
&& mkdir -p /data/m \
&& mkdir -p /data/pc
WORKDIR /data
# 安装git过程中需要进行交互,使用-y命令自动执行交互安装
# 执行apt-get update的时候,会下载一些临时文件到该目录,所以删除
RUN apt-get update \
&& apt-get install -y git \
&& rm -rf /var/lib/apt/lists/*
COPY ./m/package.json ./m/package.json
COPY ./pc/package.json ./pc/package.json
COPY ./m/package-lock.json ./m/package-lock.json
COPY ./pc/package-lock.json ./pc/package-lock.json
RUN cd /data/pc \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& npm install --registry=http://npm.example.net/
RUN cd /data/m \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& npm install --registry=http://npm.example.net/
USER root
#建立工作目录
RUN mkdir -p /data \
&& mkdir -p /data/m \
&& mkdir -p /data/pc
WORKDIR /data
# 安装git过程中需要进行交互,使用-y命令自动执行交互安装
# 执行apt-get update的时候,会下载一些临时文件到该目录,所以删除
RUN apt-get update \
&& apt-get install -y git \
&& rm -rf /var/lib/apt/lists/*
COPY ./m/package.json ./m/package.json
COPY ./pc/package.json ./pc/package.json
COPY ./m/package-lock.json ./m/package-lock.json
COPY ./pc/package-lock.json ./pc/package-lock.json
RUN cd /data/pc \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& npm install --registry=http://npm.example.net/
RUN cd /data/m \
&& source /root/.bashrc \
&& nvm use "v8.9.4" \
&& npm install --registry=http://npm.example.net/
上面的镜像大致就是这个样子的,特点就是先把依赖安装一遍,倒是打包之前再次安装就不用安装那些老大难的包了,效率极佳。不过镜像的大小就此增加了1.2G(看依赖),有些可能少一些。
其实这里还是没完的,base-nvm
这个镜像也是来之不易,并非npm一下子就能安装成功,都是安装了无数次,踩了无数个坑总结经验,而且每次前端的骚操作还让经验不可用。
FROM debian:buster
USER root
ENV TZ=Asia/Shanghai \
NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
&& sed -i "s|deb.debian.org/debian|mirrors.tuna.tsinghua.edu.cn/debian|g" /etc/apt/sources.list \
&& sed -i "s|security.debian.org/debian-security|mirrors.tuna.tsinghua.edu.cn/debian-security|g" /etc/apt/sources.list \
&& apt-get update \
&& apt-get install -y curl ca-certificates procps net-tools dnsutils iputils-ping \
telnet git build-essential bzip2 python2 autoconf automake nasm make cmake flex \
libtool libpng-dev libjpeg-dev libpng-tools zlib1g-dev imagemagick \
optipng advancecomp parallel -y \
&& curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash \
&& export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" \
&& [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" \
&& rm /bin/sh && ln -s /bin/bash /bin/sh && echo "替换sh为bash, 用于支持source命令" \
&& nvm install 8.9.4 \
&& nvm install 8.12.0 \
&& nvm install 11.15.0 \
&& nvm install 12.18.3 \
&& nvm use "v12.18.3" \
&& nvm alias default "v12.18.3" \
&& nvm cache clear \
&& rm -rf /var/lib/apt/lists/* \
&& nvm --version \
&& node -v
USER root
ENV TZ=Asia/Shanghai \
NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
&& sed -i "s|deb.debian.org/debian|mirrors.tuna.tsinghua.edu.cn/debian|g" /etc/apt/sources.list \
&& sed -i "s|security.debian.org/debian-security|mirrors.tuna.tsinghua.edu.cn/debian-security|g" /etc/apt/sources.list \
&& apt-get update \
&& apt-get install -y curl ca-certificates procps net-tools dnsutils iputils-ping \
telnet git build-essential bzip2 python2 autoconf automake nasm make cmake flex \
libtool libpng-dev libjpeg-dev libpng-tools zlib1g-dev imagemagick \
optipng advancecomp parallel -y \
&& curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash \
&& export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" \
&& [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" \
&& rm /bin/sh && ln -s /bin/bash /bin/sh && echo "替换sh为bash, 用于支持source命令" \
&& nvm install 8.9.4 \
&& nvm install 8.12.0 \
&& nvm install 11.15.0 \
&& nvm install 12.18.3 \
&& nvm use "v12.18.3" \
&& nvm alias default "v12.18.3" \
&& nvm cache clear \
&& rm -rf /var/lib/apt/lists/* \
&& nvm --version \
&& node -v
看到这里,发现底包居然是debian:buster
,是的就是它,它打包就是比centos和apline镜像好用,不过官方的方案似乎是ubuntu,差别不大。
只能说一个后端折腾前端,太难了,这些破事和我有半毛钱关系?别说为什么有那么多版本,就是有那么多,都预装省得了。还有为啥要装一堆软件,这个你去问那些node_modules的作者,安装个依赖为啥还要编译,为啥还要搞网络检查和下载,我不懂。
当前还没有任何评论