背景
众所周知使用history路由模式的前端SPA项目,都需要额外进行服务器配置,像这样:
bash
# nginx
location / {
try_files $uri $uri/ /index.html;
}
# Apache
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
# Caddy、Node等服务器
当项目足够多的时候,配置也会逐渐变得复杂起来、另外前端本地调试打包后的histroy路由页面时配置也比较麻烦。因此这里借助docker将配置文件生成镜像,后续需要调试本地history包时,就可以通过一个命令,一步到位。
下载docker
进入官网直接下载进好了:hub.docker.com/
终端输入docker -v
,有版本号输出,说明已安装成功
配置
建个文件夹放通用的配置,这里就放两个文件Dockerfile、default.conf,也可以使用命令行生成
bash
mkdir docker
cd docker
touch Dockerfile
touch default.conf
Dockerfile文件,用于生成镜像的配置文件:
csharp
# 基于nginx创建镜像
FROM nginx
# 将default.conf文件复制到镜像中的nginx配置,这样相当于镜像中使用的本地配置文件
COPY default.conf /etc/nginx/conf.d/default.conf
default.conf文件
nginx的默认配置,放到镜像中后,所有前端项目可共用。这里只处理了打包后的dist和build文件夹
ini
# 打包后的文件夹名为dist
server {
listen 80;
server_name localhost;
#charset koi8-r;
access_log /var/log/nginx/host.access.log main;
error_log /var/log/nginx/error.log error;
location / {
root /usr/share/nginx/html/dist;
# root /var/lib/docker/volumes/my-volume/_data/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# 打包后的文件夹名为build
server {
listen 81;
server_name localhost;
#charset koi8-r;
access_log /var/log/nginx/host.access.log main;
error_log /var/log/nginx/error.log error;
location / {
root /usr/share/nginx/html/build;
# root /var/lib/docker/volumes/my-volume/_data/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
基于配置创建镜像
终端执行:docker build -t docker-image-history-nginx .
命令说明:
- docker build 创建镜像
- -t 给镜像命名的参数
- docker-image-history-nginx 镜像名
- . 最后还有一个点说明是基于当前目录下的Dockerfile来创建镜像
创建后可以在docker桌面端看到刚创建的镜像:
基于镜像创建容器
创建容器后可以通过宿主机上的端口访问到容器中的端口、服务。
创建临时容器
终端执行:docker run --rm -it --name containerName -p 8888:80 imageName
临时容器会在退出终端后自动删除容器,适合本地调试、避免非必要的容器运行。
命令说明:
- docker run 运行容器
- --rm 当停止容器时自动清除该运行容器
- -it 分配一个可交互的虚拟终端
- --name 容器名的参数
- containerName 自定义容器名
- -p 端口映射的参数
- 8888:80 宿主机端口:容器端口
- imageName 创建容器使用的镜像所对应的名称
创建在后台运行的容器
终端执行:docker run -d -p 3000:80 --name containerName imageName
命令说明:
- docker exec -it nginx sh # 进入容器环境中; exit退出容器环境
- docker ps 查看运行中的容器
- docker stop containerName 停止运行中的容器
注意: 如果提示这个,说明镜像已在使用中,端口已被占用。执行docker stop containerName就可以了
vbnet
docker: Error response from daemon: driver failed programming external connectivity on endpoint build (8d8e73934d): Bind for 0.0.0.0:8765 failed: port is already allocated.
创建前端项目使用的临时容器
终端执行:
在项目根目录下执行
bash
# 针对dist文件夹
docker run --rm -it -p 8765:80 --name dist -v "$(pwd)"/dist:/usr/share/nginx/html/dist docker-image-history-nginx
# 针对build 文件夹
docker run --rm -it -p 8765:81 --name build -v "$(pwd)"/build:/usr/share/nginx/html/build docker-image-history-nginx
命令说明:
- -v 绑定挂载的参数
- $(pwd) 可以获取到当前项目的绝对路径
以上可将本地的dist/build目录挂载到容器中Nginx下的dist/build目录下,此时就可以通过8765访问到容器中的dist/build文件 并 使用了镜像中的NGINX配置。
当然,这样使用很不合理,难道每次都要写这么长一串?显然不行,我们可以使用别名简化:
bash
alias docker_dist="docker run --rm -it -p 8765:80 --name dist -v "$(pwd)"/dist:/usr/share/nginx/html/dist docker-image-history-nginx"
alias docker_build="docker run --rm -it -p 8765:81 --name build -v "$(pwd)"/build:/usr/share/nginx/html/build docker-image-history-nginx"
后续只要在项目根目录下使用docker_dist
或docker_build
命令即可。
使用梳理
npm run build
打包- 终端执行
docker_dist
或docker_build
- 访问http://localhost:8765/about
总结
当然,如果只是为了实现这个功能大可不必这样折腾。这里只是提供一种思路,展示docker的一些能力,我们可以触类旁通实现更多需要的功能。
虽说大部分服务器都只支持静态文件的处理(如:budo、anywhere等),但也有一些提供了直接支持。如在终端执行:http-server --history-api-fallback
有了--history-api-fallback
这个参数,http-server
就会把所有不直接映射到文件的路由都重定向到index.html,从而支持HTML5 History API。browser-sync、lite-server
轻量级服务器也能通过命令行直接支持。
也可以考虑使用 connect-history-api-fallback 中间件(配合express和koa框架)来实现同样的功能