0. 引言

去年写过一篇『新建带 webpacker 的 Rails 项目』,当时还是 Rails 5,需要手动加入 webpacker,而现在 Rails 6 已经默认使用 webpacker 了。一年来笔者也在之前的文章里修修补补,现在想想还是重写一篇吧。

1. 新建 Gemfile:

source 'https://rubygems.org'

gem 'rails'

注:这里之所以不直接改写成 gems.ruby-china 的镜像,是因为需要用 –force 参数覆盖已有文件,即 Gemfile 的 source 会被重写回默认源。为了避免在国内出现非常慢以至于卡在 bundle install 的情况,我在制作 docker image 的时候就直接覆盖了 Gemfile 的 source:(或者直接 –skip-bundle) RUN bundle config mirror.https://rubygems.org https://gems.ruby-china.com

2. 新建 docker-compose.yml

version: '3.7'
services:
  web:    
    image: registry.cn-shanghai.aliyuncs.com/aaron_dev/rails-base-image:v2
    command: bash -c "rm -f /app/tmp/pids/server.pid && rails s -p 5000 -b 0.0.0.0"
    volumes:
      # old string format
      - templar-sync:/app:nocopy
      # store gems locally to look into source code
      - ./.gems:/usr/local/bundle
    ports:
      - 5000:5000
    environment:
      - WEBPACKER_DEV_SERVER_HOST=webpack_dev_server

    # comment for future use
    # depends_on:
    #   - db

    # byebug, use attach
    stdin_open: true
    tty: true

  webpack_dev_server:
    image: registry.cn-shanghai.aliyuncs.com/aaron_dev/rails-base-image:v2
    command: bin/webpack-dev-server
    ports:
      - 3035:3035
    volumes:
      - templar-sync:/app:nocopy
      - ./.gems:/usr/local/bundle
    environment:
      - WEBPACKER_DEV_SERVER_HOST=0.0.0.0

  db:
    image: postgres
    volumes:
      # new format
      - type: volume
        source: dbdata
        target: /var/lib/postgresql/data
        volume:
          nocopy: true
    ports:
      - 54321:5432

volumes:
  dbdata:
  templar-sync:
    external: true

3. 新建 docker-sync.yml

version: '2'

syncs:
  templar-sync:
    src: './'

注:需要在本地 gem install docker-sync 安装 docker-sync,参考另一篇『用 docker-sync 在 Mac 进行文件系统同步』。

4. 在项目目录下运行:

docker-compose run --rm web gem install bundler
docker-sync start
docker-compose run --rm web bundle install
docker-compose run --rm web rails new [app-name] --force --database=postgresql --skip-bundle --webpack=react
  • --skip-sprockets --skip-turbolinks 参数可选,webpack 允许将 css 依旧交给 sprockets 管理;turbolinks 除非特殊需求,否则不建议关闭

注:这里补充一个知识点,在服务器上安装 docker 后,因为一般我们不会用超级用户,所以是没有权限直接运行 docker 命令的,如果不想所有命令前都加上 sudo 的话,就要把你的用户加到 docker 组里,运行如下命令然后重新登录即可:

sudo usermod -aG docker [server_username]

然后检查 /etc/group 的 docker 组知否已经加入了用户: docker:x:999:[username]

5. 修改 database.yml 如下:

default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:

6. 项目初始化完成后,修改 views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_pack_tag 'application' %>
  </head>

  <body>
    <%= yield %>

    <!-- 加载完页面再 load js -->
    <%= javascript_pack_tag 'application' %>
  </body>
</html>

7. 启动项目

docker-compose up
docker-compose exec web rails db:create
docker-compose exec web rails db:migrate

至此,我们就快速建立了一个基于 webpack 的 Rails 项目,然后加入一些基础的前端依赖,并进一步完善 webpack 的基础配置。

进入 web 容器 docker-compose exec -it web bash,运行:

yarn add bootstrap
yarn add popper.js
yarn add jquery
yarn add @fortawesome/fontawesome-free

然后修改 config/webpack/environment.js 如下:

const { environment } = require('@rails/webpacker')

const webpack = require('webpack')
/**
 * Automatically load modules instead of having to import or require them everywhere.
 * Support by webpack. To get more information:
 *
 * https://webpack.js.org/plugins/provide-plugin/
 * http://j.mp/2JzG1Dm
 * 
 * 配置文件,更改需要重启服务
 */
environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    jquery: 'jquery',
    'window.jQuery': 'jquery',
    Popper: ['popper.js', 'default']
  })
)
module.exports = environment

这个文件可以参考这两篇文章:https://joey.io/how-to-use-jquery-in-rails-5-2-using-webpack/, https://webpack.js.org/plugins/provide-plugin/

再引入这些第三方组件 app/javascript/packs/application.js

// 第三方库加载
import "bootstrap"
import "bootstrap/dist/css/bootstrap.min.css"
import "@fortawesome/fontawesome-free/css/all.min.css"

8. 允许 webpack 打包 css 文件

webpacker 4 之后,默认只会打包 js,若要启用 css 打包,需修改 config/webpacker.yml:

# Extract and emit a css file
  extract_css: true

注:因为 webpack 将所有资源都打包成 JS 的方式伺服前端,所以如果不加这条,则 css 也会随着 JS 一起加载,结果就是 html 页面显示的时候 css 还未被加载,等到 JS 加载的时候 css 才渲染,所以每次在页面刷新的时候样式会从无到有地闪动一下