Vue.js 部署笔记(2018年6月)

0. 这篇文对你有什么用

参考我是怎么部署的。然后部署你自己的 Vue.js
部署成功时间:2018年6月22号
(我在部署这件事上花了2-3天,汗)

1. 背景信息

2018年5月开始学的 Vue.js,写单页应用。
因为 Ruby on Rails 的 coffeescript/jQuery 写前端写得太烦了
我用的是 webpack-simple 模板

    vue init webpack-simple project-name

vue-router 做路由
vuex 做状态管理
.vue 单文件组件

后端:
JWT 做身份验证
Ruby on Rails 5 做后端
PostgreSQL 数据库
UCloud + Ubuntu 16.04 服务器
阿里云买的域名(备案了)

2. 为什么写这篇文

如果官方部署指南:https://vuejs.org/v2/guide/deployment.html
很好懂的话,可以一步步照做,那么也就不会有这篇文章了。
就是因为步骤写得不清楚

npm run build 之后
dist/ 有个 build.js (1.4MB) 和 build.js.map(7.6MB)
然后就不知道做什么了。
我是 Webpack 菜鸟。
WX20180619-183109@2x-1

谷歌搜 Vue.js deploy 出来的文章也没什么卵用。
所以写这篇文章

(更新)我去 Vue.js 官方提了个 Issue:
https://github.com/vuejs/vue/issues/8389
下面都说就和普通部署静态网站没啥区别,Vue.js 不需要做特殊步骤。

4. 正文

先讲最后的结果

Vue.js 部署到 https://wittcism.com/
Ruby on Rails 5 部署到 https://wittcism.com/backend/

原本想把后端部署到 https://api.wittcism.com 但因为 HTTPS 没有成功。
wildcard 通配 HTTPS 不方便搞(在这上面折腾了1天以失败告终)
付费的 HTTPS 太贵了,几千块钱,免费的 Let's Encrypt 没搞成功 wildcard。

额外讲一下 Vue + Rails

我这里虽然用了 Ruby on Rails。

但我没有用任何特殊的 gem 把 Vue 和 Rails 结合在一起(Webpacker 之类的)
我觉得那样反而费事,完全分离就好了,不搞那些乱七八糟的和 Rails 结合起来。
我不想把两个 codebase 放到一起,比如把 vue 放到 rails 的某个文件夹里。烦。
以后有前端工程师入职的话,要么把 Vue 拆出来,要么前端学一点 Rails 的知识。都不是很好的方案。所以从一开始就分离就好了。

所以 Vue.js 和 Rails 我分别弄了2个文件夹。2个 Github 私有库。

步骤

1. npm run build

这一步做完得到 dist/build.jsdist/build.js.map
-----2018-06-22---7.29.42

2. 我的图片文件和第三方的 js/css 都放到了 /static/ 目录

有人喜欢放到 public/ 目录也 OK,这里只是说一下我是取名 static/
-----2018-06-22---7.32.04

3. 把必要的文件放到一个文件夹里

index.html
/dists/
/static/
放到一个文件夹里,我这里取名 witt-front
-----2018-06-22---7.34.11

4. 文件夹 SFTP 传到服务器

因为我用的是 Mac, 我就用 Transimit(卡车 LOGO)传到服务器上去
trans

5. 配置 nginx

我建了一个 witt-front.conf 文件来放 nginx 配置,文件内容如下,供参考

upstream app_witt {
    server unix:///tmp/witt.sock;
}

server { listen 80; server_name wittcism.com www.wittcism.com; return 301 https://$server_name$request_uri; }

server { listen 443 http2 default_server; ssl on; ssl_certificate /var/www/chain/full_chain.pem; ssl_certificate_key /var/www/chain/private.key;

root /var/www/witt-front/;

# 把 Rails 挂到 /backend 目录
location ^~ /backend {
   try_files $uri/index.html $uri @app_witt;
}

location / {
    try_files /index.html =404;
}

gzip on;
gzip_types application/javascript image/* text/css;
gunzip on;

location ~* \.(jpg|jpeg|png|gif|ico)$ {
  expires 30d;
}
location ~* \.(css|js)$ {
  expires 7d;
}

error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;

location @app_witt {
    root /var/www/witticism.com/current/public;
    proxy_pass http://app_witt;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_set_header  X-Forwarded-Ssl on; # Optional
    proxy_set_header  X-Forwarded-Port $server_port;
    proxy_set_header  X-Forwarded-Host $host;
}

}

这一堆配置本质上是:

  1. 配 HTTPS
  2. 主站在 /var/www/witt-front/ 文件夹(我们的 Vue.js)
  3. /backend/ 交给 Ruby on Rails 处理

Nginx 的教程可以自己网上搜搜,我也是边学边搞,这里就不详细解释文件里每一行的含义了。
可以看 nginx 的官方文档来看 server listen root location 是什么意思。
也可以读下这个:https://www.oschina.net/translate/nginx-tutorial-basics-concepts

6. SFTP 把 witt-front.conf 传到服务器的 /var/www/

  1. witt-front.conf 这个命名没有特殊含义,我只是这样叫而已。你可以取其他名字。
  2. 放到服务器的 /var/www 也没有特定含义,你喜欢的话可以放其他地方

-----2018-06-22---7.42.17

7. 让 nginx 配置生效

Nginx 会读 /etc/nginx/sites-enabled 里的配置
但是我不喜欢把文件挪过去,所以我们用软连接:

sudo ln -s /var/www/witt-frontend.conf  /etc/nginx/sites-enabled/witt-frontend.conf

然后

# 测试配置是否正确
sudo nginx -t

如果没问题了,重启 nginx

sudo nginx -s stop sudo nginx

8. 可以了

现在访问你的主站看看行不行,我反正可以。

大小

build.js 是 1.4MB,build.js.map 是 7,8M 左右。
我看看怎么优化到 400kb 以下,其他用懒加载来做就好。
虽然只有第一次会有 1.4M,之后都会从缓存加载。但还是要优化一下。加快第一次访问的速度
4
(图片里不是第一次加载了,所以大小不是很大)

2018-6-23 更新

之前在 9.可以改进的地方 写过如下问题:

  1. 缓存问题:index.html 里的 <script src="/dist/build.js"></script> 有缓存问题。用户的浏览器看到 build.js 是同名的,就不会抓新的版本。

今天解决了这个缓存问题,思路是每次文件内容变了,让文件名也变化,让浏览器去抓取这个新文件。
具体方法是在 webpack.config.js 里面写配置,用 html-webpack-plugin 这个插件,
然后每次生成的 .js 文件名会变成 main.5fb342182d0d06595acf.js 这样,
然后 index.html 文件也是动态生成的,引入 main.5fb342182d0d06595acf.js 这个文件

可参考资料:
https://github.com/jantimon/html-webpack-plugin

以下贴出我的 webpack.config.js 全部内容

var path = require('path')
var webpack = require('webpack')
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = { entry: ‘./src/main.js’, output: { path: path.resolve(__dirname, ‘./dist’), publicPath: ‘/dist/’, filename: ‘build.js’, }, module: { rules: [{ test: /.md$/, use: ‘raw-loader’ }, { test: /.css$/, use: [ ‘vue-style-loader’, ‘css-loader’ ], }, { test: /.scss$/, use: [ ‘vue-style-loader’, ‘css-loader’, ‘sass-loader’ ], }, { test: /.sass$/, use: [ ‘vue-style-loader’, ‘css-loader’, ‘sass-loader?indentedSyntax’ ], }, { test: /.vue$/, loader: ‘vue-loader’, options: { loaders: { // Since sass-loader (weirdly) has SCSS as its default parse mode, we map // the "scss" and "sass" values for the lang attribute to the right configs here. // other preprocessors should work out of the box, no loader config like this necessary. ‘scss’: [ ‘vue-style-loader’, ‘css-loader’, ‘sass-loader’ ], ‘sass’: [ ‘vue-style-loader’, ‘css-loader’, ‘sass-loader?indentedSyntax’ ] } // other vue-loader options go here } }, { test: /.js$/, loader: ‘babel-loader’, exclude: /node_modules/ }, { test: /.(png|jpg|gif|svg)$/, loader: ‘file-loader’, options: { name: ‘[name].[ext]?[hash]’ } } ] }, resolve: { alias: { ‘vue$’: ‘vue/dist/vue.esm.js’, ‘@’: path.resolve(__dirname, ‘./src/’), }, extensions: [’*’, ‘.js’, ‘.vue’, ‘.json’] }, devServer: { historyApiFallback: true, noInfo: true, overlay: true }, performance: { hints: false }, devtool: ‘#eval-source-map’ }

if (process.env.NODE_ENV === ‘production’) { module.exports.devtool = ‘#source-map’ // http://vue-loader.vuejs.org/en/workflow/production.html module.exports.output = { path: path.resolve(__dirname, ‘./dist’), publicPath: ‘/dist/’, filename: ‘[name].[hash].js’, }, module.exports.plugins = (module.exports.plugins || []).concat([ new webpack.DefinePlugin({ ‘process.env’: { NODE_ENV: ‘"production"’ } }), new webpack.optimize.UglifyJsPlugin({ sourceMap: true, compress: { warnings: false } }), new webpack.LoaderOptionsPlugin({ minimize: true }), new CleanWebpackPlugin([‘dist’]), new HtmlWebpackPlugin({ title: ‘Wittcism’, filename: ‘./index.html’, template: ‘./template/index.html’ // template: path.resolve(__dirname, ‘index.html’), }), ]) }

9. 可以改进的地方

  1. 部署流程:我现在需要手工 SFTP 把新的 build.js 传到服务器的 /dist/ 然后清空缓存刷新页面。手工传文件这个步骤希望通过 npm run deploy 之类的命令搞定。我看看怎么优化这个。最终跑一个命令就直接更新了。

  2. 部署地点:我现在是部署到自己的 UCloud 服务器,
    其实静态资源(.html .js .jpg 之类的)
    扔到什么七牛,又拍云,AWS S3 之类的也没啥问题。只是域名的指向我要看看怎么配置才能做到。

  3. 版本回退:现在如果要做版本回退(比如前端 VUE 写错了一些东西,改正需要一些时间,先回退到之前的版本)只能手工做。

  4. 主站还没做响应式(media query),来方便手机浏览。

使用 Hugo 构建
主题 StackJimmy 设计