学习Rails与Webpacker

241 阅读5分钟

在没有Webpacker的情况下创建一个新的Rails应用程序

最小的应用程序

$> rails new myapp --minimal
$> cd myapp

minimal标志的意思是 "请安装一个依赖性尽可能小的默认Rails应用程序"。

添加最基本的文件

现在创建一个默认的路由、控制器和视图

# inside config/routes.rb  
Rails.application.routes.draw do  
  get "welcome/index"  
  root to: "welcome#index"  
end  
# inside app/controllers/welcome_controller.rb  
class WelcomeController < ApplicationController  
end  
<!-- inside app/views/welcome/index.html.erb -->  
<h1> Hello, Rails and Webpack ! </h1>

并运行Rails应用程序

$/myapp> bin/rails server

在localhost:3000处打开浏览器,你应该看到 "你好,Rails和Webpack!"

在Rails中添加Webpacker gem

打开Gemfile,添加这一行。

# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 5.0'

停止服务器,并运行

$myapp> bundle install

并且

$myapp> bin/rails webpacker:install

以下是最后一条命令所做的事情(从输出中提取,并进行了简化)。

      create  config/webpacker.yml
      create  config/webpack
      create  config/webpack/development.js
      create  config/webpack/environment.js
      create  config/webpack/production.js
      create  config/webpack/test.js
      create  postcss.config.js
      create  babel.config.js
      create  .browserslistrc
      The JavaScript app source directory already exists (app/javascript)
      create    bin/webpack
      create    bin/webpack-dev-server
      append  .gitignore
      run  yarn add @rails/webpacker@5.2.1 from "."

现在我们的package.json看起来像这样。

{
  "dependencies": {
    "@rails/webpacker": "5.3.0",
    "webpack": "^4.46.0",
    "webpack-cli": "^3.3.12"
  },
  "devDependencies": {
    "webpack-dev-server": "^3.11.2"
  }
}

这突出了webpacker只是webpack的一个封装器。

为Webpacker改变Rails的默认目录

Rails和Webpack(er)的恼人之处在于,默认集成认为只有JavaScript应该由Webpack处理,而其他资产应该由一个较早的gem(Sprokets)处理。现在webpacker已经完全成熟,所以我们只使用它。

app/javascript 改名为app/frontend ,像这样。

$/myapp> mv app/javascript app/frontend  

在config/webpacker.yml中,改变文件夹的名称,如下所示。

# Inside webpacker.yml, first lines  
default: &default  
  source_path: app/frontend # Change here  
  source_entry_path: packs

添加第一个前端文件

从上面的配置你可以猜到,Webpack会把app/frontend/packs目录下的任何文件变成一个 "包"(可以在html页面中引用的编译文件)。

因此,让我们添加app/frontend/packs/mainjs.js

// inside app/frontend/packs/mainjs.js
console.log("Hello from mainjs")

用Rails构建(web)包

在运行本地服务器时,Rails会自动运行一些构建,但在本教程中,我们想了解到底发生了什么。

到目前为止,你应该在你的应用程序的根部有一个/public文件夹,但没有任何/public/packs文件夹,这是webpacker的默认构建输出。

让我们来构建我们的包包,运行

$/myapp> bin/rails assets:clobber
$/myapp> bin/rails webpacker:compile

第一行清除了之前的任何构建,第二行运行实际的构建。

现在让我们检查一下发生了什么

**bin/rails webpacker:compile**

**Compiling...**

**Compiled all packs in /Users/david/workspace/myapp/public/packs**

**warning package.json: No license field**

  

**Hash: 242563483b6f56b94cc3**

**Version: webpack 4.46.0**

**Time: 1316ms**

**Built at: 04/12/2021 9:58:18 AM**

**Asset Size  Chunks Chunk Names**

**js/mainjs-266dceea7f600337d3ed.js  1 KiB 0  [emitted] [immutable]  mainjs**

**js/mainjs-266dceea7f600337d3ed.js.br  467 bytes  [emitted]**

**js/mainjs-266dceea7f600337d3ed.js.gz  528 bytes  [emitted]**

**js/mainjs-266dceea7f600337d3ed.js.map 4.67 KiB 0  [emitted] [dev]  mainjs**

**js/mainjs-266dceea7f600337d3ed.js.map.br 1.59 KiB  [emitted]**

**js/mainjs-266dceea7f600337d3ed.js.map.gz 1.78 KiB  [emitted]**

**manifest.json  329 bytes  [emitted]**

**manifest.json.br  122 bytes  [emitted]**

**manifest.json.gz  135 bytes  [emitted]**

**Entrypoint mainjs = js/mainjs-266dceea7f600337d3ed.js js/mainjs-266dceea7f600337d3ed.js.map**

**[0] ./app/frontend/packs/mainjs.js 33 bytes {0} [built]**

Webpack创建了一堆文件,即使我们到目前为止创建了一个简单的JS文件和一个简单的console.log。打开public/packs/js文件夹来注意它。

Many pages

许多文件

好的,对于一个文件 : 有六个可能的扩展名。

也看看manifest.json文件。

{
  "entrypoints": {
    "mainjs": {
      "js": [
        "/packs/js/mainjs-266dceea7f600337d3ed.js"
      ],
      "js.map": [
        "/packs/js/mainjs-266dceea7f600337d3ed.js.map"
      ]
    }
  },
  "mainjs.js": "/packs/js/mainjs-266dceea7f600337d3ed.js",
  "mainjs.js.map": "/packs/js/mainjs-266dceea7f600337d3ed.js.map"
}

manifest.json是来帮忙的。如果一个HTML文件正在寻找一个名为 "mainjs "的js文件,它就会向manifest.json询问具体位置。

用于 JavaScript 的 Webpacker

上面的例子是关于一个JavaScript文件的,所以好消息是:我们已经完成了一半的工作。

引用一个现有的包

现在通过修改主布局(app/views/layouts/application.html.erb)将我们的mainjs文件引用到HTML中。

<!-- inside app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
  <head>
    <title>Rails and Webpack</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    
    <!-- Remove stylesheet_link_tag  -->
    <!-- Add the line below  -->
    <%= javascript_pack_tag 'mainjs' %>    
  </head>

  <body>
    <%= yield %>
  </body>
</html>

停止并重启本地Web服务器

$/myapp> bin/rails server

在localhost:3000处打开浏览器,查看浏览器的开发工具中是否显示日志信息。

Displayed log<

显示的日志

使用ES6模块

如果你想要一个普通的ES6模块,它不会是一个包,只需添加一个文件夹app/frontend/js,像这样。

// inside app/frontend/js/magicAdd.js
const  magicAdd = (a, b) => {
  return a + b;
}
export default  magicAdd;

并从包中引用这个文件。

// inside app/frontend/packs/mainjs.js

import magicAdd from '../js/magicAdd.js'

let a = magicAdd(2, 4);

// remove old console.log, and replace by the one below
console.log(`From mainjs, magicAdd result is ${a}`)

现在打开你的浏览器,检查浏览器的控制台,看是否一切正常。

样式表的Webpacker

首先,把每个extract_css: false 改为extract_css: true 里面的config/webpacker.yml 。否则webpack将无法检测到scss文件作为一个可能的包。

现在,创建一个包,但这一次,它应该是一个scss文件(app/frontend/packs/mainstyle.scss)。

// inside app/frontend/packs/mainstyle.scss  
 
// Just a quick ugly style to see if our CSS works  
h1 {  
  text-decoration: underline;  
}  

仅仅一个文件在生产就绪的应用程序中是不够的,所以,像javascript一样,让我们看看如何引用另一个文件。

// inside app/frontend/css/mycomponent.scss
h1 {  
  font-style: italic;
}  

更新mainstyle.scss以引用这个新的自定义组件。

// inside app/frontend/packs/mainstyle.scss  
@import "../css/mycomponent.scss"; 
 
// Just a quick ugly style to see if our CSS works  
h1 {  
  text-decoration: underline;  
}  

很好!所以现在让我们告诉主布局,我们想使用webpack的样式表。

<!-- inside app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
  <head>
    <title>My title</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    
    <!-- Add line below, stylesheed_pack_tag -->
    <%= stylesheet_pack_tag 'mainstyle' %>
    <%= javascript_pack_tag 'mainjs' %>
  </head>

  <body>
    <%= yield %>

  </body>
</html>

停止你的本地Web服务器,并运行

$/myapp> bin/rails assets:clobber
$/myapp> bin/rails webpacker:compile

检查你的manifest.json文件,并再次运行你的本地Web服务器,你应该看到一个标题是以斜体和下划线显示的。

字体家族的Webpacker

在这里下载 "Asap "字体,将其解压,并将名为Asap-VariableFont_wght.ttf的文件复制/粘贴到app/frontend/font/Asap/Asap-VariableFont_wght.ttf

然后添加一个文件font_faces.scss到app/frontend/css/font_faces.scss

@font-face {
  font-family: 'Asap';
  src: url('../font/Asap/Asap-VariableFont_wght.ttf') format('woff2 supports variations'),
       url('../font/Asap/Asap-VariableFont_wght.ttf') format('woff2-variations');
  font-weight: 100 1000;
}

更新mainstyle.scss以引用该字体。

// inside app/frontend/packs/mainstyle.scss  
// Add the line below on the top of the file
@import '../css/font_faces';
@import "../css/mycomponent.scss"; 
 
// Just a quick ugly style to see if our CSS works  
h1 {  
  // And add this line below to ensure font-family works
  font-family: 'Asap';
  text-decoration: underline;  
}  

再次,停止你的本地网络服务器,并运行

$/myapp> bin/rails assets:clobber
$/myapp> bin/rails webpacker:compile

检查你的manifest.json文件,并再次运行你的本地网络服务器,你应该看到一个显示为斜体、下划线的标题......并且字体名称为 "Asap"。

图片的Webpacker

创建一个名为rectangle.svg的SVG文件到app/frontend/img/rectangle.svg

<!-- inside app/frontend/img/rectangle.svg -->
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <path d="M10 10 H 90 V 90 H 10 Z" fill="red" stroke="black"/>
</svg>

然后在主JS文件中添加一行,像这样。

// inside app/frontend/packs/mainjs.js

// Add the line below
const images = require.context('../img', true)

// Everything else remain the same

现在这个图片可以从任何其他文件中引用了

<!-- inside app/views/welcome/index.html.erb -->  
<h1> Hello, Rails and Webpack ! </h1>
<%= image_pack_tag 'media/img/rectangle.svg', alt: 'A rectangle' %>

请注意,webpack会在路径中加入 "media "前缀。

再次,停止你的本地Web服务器,并运行

$/myapp> bin/rails assets:clobber
$/myapp> bin/rails webpacker:compile

检查你的manifest.json文件,并再次运行你的本地Web服务器,打开浏览器,嗒嗒嗒:你现在应该看到出现的矩形。

总结

我们已经看到了如何让 Webpacker 与 Rails 一起工作。对于Javascript文件、样式表、图像和字体。通过一个真实的例子,从头开始。别担心,你不必在每次改动时都编译资产和重启服务器。本教程需要这样做,只是因为我们在每个步骤中都添加了一种新的资产。