概述
前端工程使用vue-cli-service
进行构建,生成dist
静态资源目录,其中包括html
、css
、javascript
以及其他项目中使用到的所有资源。
在生产环境中,我们通常使用Nginx
开启访问服务,并定位其访问目录至dist
目录下的index.html
,以此来实现前端工程的访问。
不仅如此,为了使得前端发起请求时,可以正确访问到后端服务,也需要在nginx
中配置相应的代理,使得访问过程在同域
中进行,以达到Cookie
共享的目的。
当然,服务部署的形式可以有多种,上述的部署方式也是较为常用的部署方式。
部署
- 使用
production
模式进行打包 - 使用
dotenv-webpack
插件启用process.env
- 配置
chainWebpack
调整资源加载顺序 - 使用
thread-loader
进行打包加速
性能调优
- 使用
compression-webpack-plugin
插件进行压缩打包 - 启用
Nginx
的gzip
和gzip_static
功能 - 使用
OSS
加速静态资源访问(可选)
使用production
模式进行打包
在package.json中添加执行脚本
{
"scripts": {
"build": "vue-cli-service build --mode production"
}
}
执行打包命令
npm run build
使用dotenv-webpack
插件启用process.env
参考资料
在package.json中添加依赖或使用npm
安装
{
"devDependencies": {
"dotenv-webpack": "1.7.0"
}
}
npm install dotenv-webpack@1.7.0 --save-dev
在vue.config.js中添加配置
const Dotenv = require('dotenv-webpack');
module.exports = {
publicPath: '/',
productionSourceMap: false,
lintOnSave: false,
configureWebpack: {
plugins: [
new Dotenv()
]
}
};
.env
加载顺序
使用不同模式,加载的文件不同。文件按照从上到下依次加载。
-
development
- .env
- .env.development
-
production
- .env
- .env.production
配置chainWebpack
调整资源加载顺序
chainWebpack
对资源加载顺序取决于name
属性,而不是priority
属性。如示例中的加载顺序为:chunk-a --> chunk-b --> chunk-c。
通常情况下,我们希望第三方资源优先加载,@kunlun会覆盖第三方资源(如css样式在同级别选择器中优先级取决于加载顺序),项目中的资源优先级最高。
module.exports = {
publicPath: '/',
productionSourceMap: false,
lintOnSave: false,
chainWebpack: (config) => {
config.plugin('html').tap((args) => {
args[0].chunksSortMode = (a, b) => {
if (a.entry !== b.entry) {
// make sure entry is loaded last so user CSS can override
// vendor CSS
return b.entry ? -1 : 1;
} else {
return 0;
}
};
return args;
});
config.optimization.splitChunks({
...config.optimization.get('splitChunks'),
cacheGroups: {
libs: {
name: 'chunk-a',
test: /[\\/]node_modules[\\/]/,
priority: 1,
chunks: 'initial',
maxSize: 6000000,
minSize: 3000000,
maxInitialRequests: 5
},
kunlun: {
name: 'chunk-b',
test: /[\\/]node_modules[\\/]@kunlun[\\/]/,
priority: 2,
chunks: 'initial',
maxSize: 6000000,
minSize: 3000000,
maxInitialRequests: 5
},
common: {
name: 'chunk-c',
minChunks: 2,
priority: 3,
chunks: 'initial',
reuseExistingChunk: true
}
}
});
}
};
使用thread-loader
进行打包加速
参考资料
在package.json中添加依赖或使用npm
安装
{
"devDependencies": {
"thread-loader": "3.0.4"
}
}
npm install thread-loader@3.0.4 --save-dev
在vue.config.js中添加配置
const path = require('path');
module.exports = {
publicPath: '/',
productionSourceMap: false,
lintOnSave: false,
configureWebpack: {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
include: path.resolve('src'),
use: [
{
loader: 'thread-loader',
options: {
workers: 3
}
}
]
}
]
}
}
};
使用compression-webpack-plugin
插件进行压缩打包
参考资料
在package.json中添加依赖或使用npm
安装
{
"devDependencies": {
"compression-webpack-plugin": "4.0.1"
}
}
npm install compression-webpack-plugin@4.0.1 --save-dev
在vue.config.js中添加配置
const CompressionPlugin = require("compression-webpack-plugin");
module.exports = {
publicPath: '/',
productionSourceMap: false,
lintOnSave: false,
configureWebpack: {
plugins: [
new CompressionPlugin({
algorithm: 'gzip',
test: /\.js$|\.html$|\.css$/,
filename: '[path].gz[query]',
minRatio: 0.8,
threshold: 10240,
deleteOriginalAssets: false
})
]
}
}
启用Nginx
的gzip
和gzip_static
功能
参考资料
在nginx.conf中添加配置
该配置支持位置:http
、server
、location
。
http {
gzip_static on;
gzip_proxied expired no-cache no-store private auth;
gzip on;
gzip_min_length 1024;
gzip_buffers 32 4k;
gzip_comp_level 5;
gzip_vary on;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_disable "MSIE [1-6]\.";
}
常用Nginx
配置参考
server {
listen 80;
listen [::]:80;
server_name localhost;
# access_log /var/log/nginx/host.access.log main;
root /opt/pamirs;
location / {
try_files $uri $uri/ /index.html;
index index.html index.htm;
expires 1d;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache nginx_cache;
proxy_cache_valid 200 302 1d;
proxy_cache_valid 404 10m;
proxy_cache_valid any 1h;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
if ($request_filename ~* ^.*?.(html|htm|js)$) {
add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
}
}
location /pamirs {
proxy_pass http://127.0.0.1:8091;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /pamirs/openapi {
proxy_pass http://127.0.0.1:8092;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
PS:127.0.0.1:8091
表示服务端访问地址;127.0.0.1:8092
表示服务端EIP访问地址;
使用本地OSS
的Nginx
配置参考
server {
location /file/upload {
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /static {
alias /opt/pamirs/static;
add_header Content-Disposition attachment;
add_header Content-Type application/octet-stream;
}
location /css/static {
alias /opt/pamirs/static;
add_header Content-Disposition attachment;
add_header Content-Type application/octet-stream;
}
}
PS:127.0.0.1:8091
表示服务端访问地址;
使用OSS
加速静态资源访问(可选)
本文以阿里云为例进行讲解,其他OSS
可自行翻阅资料进行配置。
参考资料
在package.json中添加依赖或使用npm
安装
{
"devDependencies": {
"webpack-aliyun-oss": "0.5.2"
}
}
npm install webpack-aliyun-oss@0.5.2 --save-dev
在vue.config.js中添加配置,并填入OSS配置
const WebpackAliyunOss = require('webpack-aliyun-oss');
const OSS_URL = 'https//';
const OSS_DIST = "/pamirs/oinone/kunlun"
const OSS_REGION = '';
const OSS_ACCESS_KEY_ID = '';
const OSS_ACCESS_KEY_SECRET = '';
const OSS_BUCKET = '';
const UNIQUE_KEY = Math.random();
module.exports = {
publicPath: `${OSS_URL}/${OSS_DIST}/${UNIQUE_KEY}/`,
productionSourceMap: false,
lintOnSave: false,
configureWebpack: {
plugins: [
new WebpackAliyunOss({
from: ['./dist/**/**', '!./dist/**/*.html'],
dist: `${OSS_DIST}/${UNIQUE_KEY}`,
region: OSS_REGION,
accessKeyId: OSS_ACCESS_KEY_ID,
accessKeySecret: OSS_ACCESS_KEY_SECRET,
bucket: OSS_BUCKET,
timeout: 1200000,
deleteOrigin: true,
deleteEmptyDir: true,
overwrite: true
})
]
}
};
Q/A
为什么需要使用压缩打包方式生成.gz
文件?
通过Nginx
启用gzip
压缩虽然也能达到压缩传输的目的,但gzip
模块实际上在每次传输时(非disk cache)都会耗费cpu性能对文件内容进行压缩后再进行传输。
文中对Nginx
的优化不仅启用了gzip
模块,还启用了gzip_static
模块。而gzip_static
模块在传输时默认会优先使用.gz
已经压缩好的文件直接进行传输。这种方式在支持gzip_static
浏览器(如Chrome)上可以大大提高访问性能,并且可以减少服务器压力,综合提高服务器响应能力。
演示文件传输
使用gzip
的响应头
使用gzip_static
的响应头
使用OSS
而不是通过Nginx
进行静态文件的分发有什么好处?
一般来说,云厂商提供的OSS
服务不仅是一个高性能的对象存储服务,搭配云厂商提供的CDN
加速服务,可以不限地域的使用云资源,以此来提高页面响应速度。
阿里云的OSS
是否也支持gzip
和gzip_static
?
支持
附录
下面是在本文中提到的完整配置
package.json
{
"scripts": {
"build": "vue-cli-service build --mode production"
},
"devDependencies": {
"compression-webpack-plugin": "4.0.1",
"dotenv-webpack": "1.7.0",
"thread-loader": "3.0.4",
"webpack-aliyun-oss": "0.5.2"
}
}
vue.config.js
在该配置中,当process.env
包含DEPLOY=online
时自动使用OSS
。
const Dotenv = require('dotenv-webpack');
const path = require('path');
const WebpackAliyunOss = require('webpack-aliyun-oss');
const CompressionPlugin = require("compression-webpack-plugin");
let BASE_URL = '/';
const { DEPLOY, OSS_REGION, OSS_DIST, OSS_URL, OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET, OSS_BUCKET } = process.env;
const UNIQUE_KEY = Math.random();
switch (DEPLOY) {
case 'online':
BASE_URL = `${OSS_URL}${UNIQUE_KEY}/`;
break;
default:
BASE_URL = '/';
}
module.exports = {
publicPath: BASE_URL,
productionSourceMap: false,
lintOnSave: false,
configureWebpack: {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
include: path.resolve('src'),
use: [
{
loader: 'thread-loader',
options: {
workers: 3
}
}
]
}
]
},
plugins: [
new Dotenv(),
new CompressionPlugin({
algorithm: 'gzip',
test: /\.js$|\.html$|\.css$/,
filename: '[path].gz[query]',
minRatio: 0.8,
threshold: 10240,
deleteOriginalAssets: false
}),
DEPLOY === 'online'
? new WebpackAliyunOss({
from: ['./dist/**/**', '!./dist/**/*.html'],
dist: `${OSS_DIST}/${UNIQUE_KEY}`,
region: OSS_REGION,
accessKeyId: OSS_ACCESS_KEY_ID,
accessKeySecret: OSS_ACCESS_KEY_SECRET,
bucket: OSS_BUCKET,
timeout: 1200000,
deleteOrigin: true,
deleteEmptyDir: true,
overwrite: true
})
: () => { }
]
},
chainWebpack: (config) => {
config.plugin('html').tap((args) => {
args[0].chunksSortMode = (a, b) => {
if (a.entry !== b.entry) {
// make sure entry is loaded last so user CSS can override
// vendor CSS
return b.entry ? -1 : 1;
} else {
return 0;
}
};
return args;
});
config.optimization.splitChunks({
...config.optimization.get('splitChunks'),
cacheGroups: {
libs: {
name: 'chunk-a',
test: /[\\/]node_modules[\\/]/,
priority: 1,
chunks: 'initial',
maxSize: 6000000,
minSize: 3000000,
maxInitialRequests: 5
},
kunlun: {
name: 'chunk-b',
test: /[\\/]node_modules[\\/]@kunlun[\\/]/,
priority: 2,
chunks: 'initial',
maxSize: 6000000,
minSize: 3000000,
maxInitialRequests: 5
},
common: {
name: 'chunk-c',
minChunks: 2,
priority: 3,
chunks: 'initial',
reuseExistingChunk: true
}
}
});
},
devServer: {
port: 8080,
disableHostCheck: true,
progress: false,
proxy: {
'/pamirs': {
changeOrigin: true,
target: 'http://127.0.0.1:8080'
}
}
}
};
Oinone社区 作者:张博昊原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/6796.html
访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验