在 Rails 使用 Webpacker 導入 vue-element-admin

前言

小弟最近工作開始寫 Ruby,那就來分享一下最近遇到的突破吧。
這次遇到的專案原本後端是 Ruby 前端是 Angular 1.X,
在2020年還可以看到 Angular已經來到 Angular 9 (released on 2020/2/7)
前端還在上古時代,這樣還能號稱 科技公司? 
這樣說有點誇張,因爲其他新的專案已經使用 vue 
為了要讓公司的技術單純化,同事提出了混用 vue, Angular,新的頁面使用 vue,舊的頁面使用 Angular 逐一淘汰舊的頁面。

這邊使用的版本
Ruby: v2.5.7
Rails: v4.2.11
webpacker: v4.0.2
vue-element-admin: v4.0.0

Rails

Rails 是很標準的MVC 架構,對於 file structure與 naming 有這強烈的規定。
要混用就必須了解 Rails 的 route 設定,Controller,view的位置,才能更好理解。
設計的目標: root(/) 走舊的 Angular, /vue/ 下走新的 vue
(如果 是新的專案 可以直接跳過這一單元)

route 

config/routes.rb
Rails.application.routes.draw do
root 'page#index' #original Angular entry point
get '/vue/' => 'vue#index' # new Vue entry point
get '/vue/*route' => 'vue#index'
# for History mode remove # in url (https://forum.vuejs.org/t/vue-2-0-how-to-remove-in-url/748)
end
view raw routes.rb hosted with ❤ by GitHub


這樣 root 會去問 page_controller
vue 會去問 vue_controller

controller


app/controllers/page_controller.rb

class PageController < ApplicationController
def index
end
end

這跟一般的controller 沒什麼不一樣,如果是default application_controller.rb 是可以略掉的

app/controllers/vue_controller.rb

class VueController < ApplicationController
layout 'vue'
def index
end
end

因為 vue 是新的 layout,我們這邊規定,這個controller 要用特定的layout,layout的設定請看下面的 view


view

app/views/layouts/application.html.erb

<!DOCTYPE html>
<html ng-app="app">
<head>
<title>Angular App</title>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
<%= csrf_meta_tags %>
</head>
<body>
</body>
<!-- angular templating -->
<ui-view></ui-view>
<%= yield %>
</html>


這裏是原本 angular 的entry layout
這裡寫  ‘application’ 會對應到  app/assets/javascripts/application.js
detail 要怎麼在 Rails 寫 Angular 可以參考這篇

app/views/layouts/vue.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Vue website</title>
<%= javascript_pack_tag 'main' %>
<%= stylesheet_pack_tag 'main' %>
<%= csrf_meta_tags %>
<meta name="viewport" content="width=device-width">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div class="container" data-behavior="app">
<%= yield %>
</div>
</body>
</html>
view raw vue.html.erb hosted with ❤ by GitHub


這是簡單的 rails layout for vue,
這裏是使用下面的 webpacker 套件來做綁定位置
這裏的main 會對應到 app/javascript/packs/main.js
也可以改自己喜歡的名字, 把只要 檔名 要一致,rails 才能幫你對應到
default 喜歡用 application.js 但是上面Angular已經用過, 所以這邊換了名字


其中最重要的是
<%= stylesheet_pack_tag 'main' %>
view raw vue1.html.erb hosted with ❤ by GitHub

這個沒有的話,在production 是 style 不會 載入

Webpacker

webpacker 是 webpack rails 的套件,讓使用者簡單在rails 使用webpack 打包 javascript以及圖、css等。

Webpack

webpack 是javascript 的靜態model打包工具。

主要核心概念:

  • 入口 (webpacker 會幫忙設定,參考 source_entry_path)
  • 輸出 (webpacker 會幫忙設定,參考 public_output_path)
  • loader
webpack 只能理解 javascript 與 JSON, loader 可以讓webpack 知道怎麼去處理其他類型的檔案,並轉換成有效的model。
example
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
}
};


  • plugin
主要做loader不能的事情,像是打包優化,資源管理,環境變數設定。
  • mode (環境 development, production, webpacker 會幫忙設定)

Pre-Install

node 

請使用 nvm 安裝 lts 的版本

yarn 

npm install -g yarn
view raw gistfile1.txt hosted with ❤ by GitHub

Install

如果是 Rails 5.1+ 可以直接用 --webpack
# Available Rails 5.1+
rails new myapp --webpack
view raw rails.sh hosted with ❤ by GitHub


這邊使用 Rails 4 要手動加gemfile
# Gemfile
gem 'webpacker', '~> 4.x'
view raw gistfile1.txt hosted with ❤ by GitHub


加完之後就可以執行
bundle
bundle exec rake webpacker:install # rails version < 5
yarn upgrade
view raw gistfile1.txt hosted with ❤ by GitHub


會安裝 default 檔案

app
├── javascript
│ ├── packs
│ │ │ # only webpack entry files here 如果這裡很多檔案,compile會跑很久,其他檔案放到下面 src
│ │ └── application.js
│ └── src
│ │ # 你的code
│ └── App.vue
└── views/layouts
└── application.html.erb
bin
├── webpack
└── webpack-dev-server
config
├── webpack
│ ├── development.js
│ ├── environment.js
│ ├── production.js
│ └── test.js
└── webpacker.yml
view raw gistfile1.txt hosted with ❤ by GitHub


說明:
app/javascript/packs/application.js
 這裡是將需要import 進來的檔案放入這裡,並在這裡注入vue

app/javascript/src/App.vue
 這裡是實際開發的地方

app/view/layouts/application.html.erb
 這是layout的設定,上面有提到

bin/webpack-dev-server
 這是在開發 時,webpack server,會將 前端跑在另外的port上面,webpacker 會幫忙把rails route,並將前端綁定到application.html.erb 內,呈現出來。

config/webpack
 這些是 webpack 設定 可以看 這裡,或是下面會講到。

config/webpacker.yml
 這些是webpacker 的設定,detail,或是下面會講到。

其中我因應各人需求將檔案換成下列

app/views/layouts/application.html.erb -> app/views/layouts/vue.html.erb
app/javascript/packs/application.js -> app/javascript/packs/main.js

Development

# 前後端分開執行
rails s # 後端
bin/webpack-dev-server # 前端
view raw gistfile1.txt hosted with ❤ by GitHub

也可以使用 foreman

Production

webpacker 已經把 webpacker:compile 放入 assets:precompile 所以 每次上版,只要執行 assets:precompile不用另外執行。

vue-element-admin

vue-element-admin 是 非常厲害的後台模板,可以簡單的讓我們套用樣式

這裡我們將他導入進來

Copy & Paste


先download 全部的檔案
將 $(vue-element-admin-project)/src 下面的檔案全部(除了main.js)複製到 app/javascript/src
將 $(vue-element-admin-project)/src/main.js 複製到 $(project)/app/javascript/packs/main.js

app/javascript/packs/main.js
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})

改成
document.addEventListener('DOMContentLoaded', () => {
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
})
view raw main.new.js hosted with ❤ by GitHub

Config webpack


到 vue-element-admin 下
npm install
view raw gistfile1.txt hosted with ❤ by GitHub


因為 vue-element-admin 使用 vue-cli 執行
npx vue-cli-service inspect --verbose --mode production > webpack.prod.js
npx vue-cli-service inspect --verbose > webpack.dev.js
view raw inspect.sh hosted with ❤ by GitHub

webpack.prod.js 是 production 的設定
webpack.dev.js 是 development 的設定

建立 config/webpack/custom.js

將共用的rule設定放在 custom.js
module.exports = {
devtool: 'cheap-source-map',
entry: ['babel-polyfill', path.resolve(__dirname, '..', '..', 'app', 'javascript', 'packs', 'main.js')],
resolve: {
alias: {
'@': path.resolve(__dirname, '..', '..', 'app', 'javascript', 'src'),
'vue$': 'vue/dist/vue.common.js'
}
},
output: {
filename: 'js/[name].js',
chunkFilename: 'js/[id].chunk.js',
},
module: {
noParse: /^(vue|vue-router|vuex|vuex-router-sync)$/,
rules: [
{
test: /\.vue$/,
use: [
{
loader: 'cache-loader',
options: {
cacheDirectory: nodeModuleResolve('.cache/vue-loader')
}
},
]
}
// skip other rule
]
}
}
view raw custom.js hosted with ❤ by GitHub


到 config/webpack/environment.js 加入剛剛設定的custom.js
const { environment } = require('@rails/webpacker')
const customConfig = require('./custom')
environment.config.merge(customConfig)


webpack 的 plugin 可以直接在 config/webpack/environment.js 設定

const { environment } = require('@rails/webpacker')
const { VueLoaderPlugin } = require('vue-loader')
environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin())


在加入vue-cli 的設定之後,會有些衝突,我發現是因為webpacker 已經設定(像是 css, sass)等,必須移除。

config/webpack/environment.js

const { environment } = require('@rails/webpacker')
environment.loaders.delete('css')
environment.loaders.delete('moduleCss')
environment.loaders.delete('moduleSass')


其他 webpacker 的設定,可以在config/webpack/ 內的檔案下console.log(environment)看看裡面的 內容

Config webpacker.yml

at config/webpacker.yml
static_assets_extensions:
- .jpg
- .jpeg
- .png
- .gif
- .tiff
- .ico
- .svg
- .eot
- .otf
- .ttf
- .woff
- .woff2
extensions:
- .vue
- .mjs
- .js
- .sass
- .scss
- .css
- .module.sass
- .module.scss
- .module.css
- .png
- .svg
- .gif
- .jpeg
- .jpg


將 不需要的移除,變成下面的樣子,不然sass 會有問題

static_assets_extensions:
- .jpg
- .jpeg
- .png
- .gif
extensions:
- .vue
- .mjs
- .js
- .png
- .gif
- .jpeg
- .jpg


===
以上是我在 Rails 中透過 webpacker使用 vue-element-admin 的過程

如果在使用過程中還遇到其他問題,歡迎提出。



留言

  1. As claimed by Stanford Medical, It is really the SINGLE reason women in this country live 10 years longer and weigh 42 pounds lighter than we do.

    (And really, it has NOTHING to do with genetics or some secret exercise and really, EVERYTHING about "how" they are eating.)

    BTW, What I said is "HOW", not "what"...

    CLICK on this link to uncover if this brief quiz can help you unlock your real weight loss possibility

    回覆刪除

張貼留言

這個網誌中的熱門文章

上海的五險一金

中國上海養老保險個人帳戶終止、醫療保險清算

前十字韌帶斷裂、重建之保險