假设你刚买了一个Bootstrap模板(或任何HTML模板),想把它整合到Rails 6上,你该从哪里开始?🤔
本教程旨在指导整合过程,概述了几个主要步骤,整个整合过程可能需要几个小时到几天,取决于你买的模板有多大或多复杂。
内容表
我将在本教程中使用Front Bootstrap主题,你可以使用你自己的主题,我想步骤应该差不多。

我建议创建一个控制器和一个视图,如果你要创建一个新的Rails应用,在继续之前先将根路径路由到这个视图。由于默认的 "Yay you are on Rails "页面没有使用我们将在下一部分安装的NPM包,因此,如果出现问题,你不会看到任何错误,我们不希望这样,因为我们希望能够解决潜在的JavaScript问题。
许多模板的前台都依赖NPM包,我们可以通过导航到模板的javascript或vendor文件夹来检查他们使用的NPM包。

需要注意的是,并不是所有模板使用的Javascript库都可以作为NPM包使用,有些Javascript库可能是模板专有的,或者只是在NPM上没有。
你可以通过在NPM网站上搜索来检查Javascript库是否可以作为包使用:www.npmjs.com。
列出NPM上可用的库的名字,然后在终端使用yarn add ,以我的例子为例,将它们全部安装。
yarn add @yaireo/tagify appear bootstrap popper.js chart.js chartjs-chart-matrix chartjs-plugin-datalabels circles.js clipboard datatables datatables.net-buttons daterangepicker dropzone flag-icon-css flatpickr ion-rangeslider jquery-mask-plugin jquery-migrate jquery-validation jszip leaflet list.js pdfmake pwstrength-bootstrap quill sortablejs table-edits
(如果你使用bootstrap包,确保同时安装 "popper.js "包,因为有些bootstrap组件依赖于popper.js。
现在我们已经安装了这些NPM包,让我们在app/javascript/packs/application.js的主包文件中导入它们。
/* app/javascript/packs/application.js */
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
require("@rails/ujs").start()
require("turbolinks").start()
// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)
import "@yaireo/tagify";
import "appear";
import "bootstrap";
import "chart.js";
import "chartjs-chart-matrix";
import "chartjs-plugin-datalabels";
import "circles.js";
import "clipboard";
import "datatables";
import "datatables.net-buttons";
import "daterangepicker";
import "daterangepicker/daterangepicker.css";
import "dropzone";
import "flag-icon-css/css/flag-icon.min.css"
import "flatpickr";
import "flatpickr/dist/flatpickr.min.css";
import "ion-rangeslider";
import "jquery-mask-plugin";
import "jquery-migrate";
import "jquery-validation";
import "jszip";
import "leaflet";
import "list.js";
import "pdfmake";
import "pwstrength-bootstrap/dist/pwstrength-bootstrap.min";
import "quill";
import "select2";
import "select2/dist/css/select2.min.css";
import "sortablejs";
好了,现在我们已经导入了这些NPM包,让我们运行rails服务器和webpack开发服务器来检查一切是否工作正常。
然后打开一个新的终端标签/窗口。
前往http://localhost:3000,哦,不,有一个错误!

什么是 "找不到模块。错误 不能解决'appear'"错误是什么意思?这意味着application.js中的**import 'appear';**行失败了,因为没有'appear'模块需要被导入。
通常,现代的Javascript包会把它们的功能以模块的形式输出,这样我们就可以很容易地导入它们。例如**@yaireo/tagify库,我们可以导航到node_modules/@yaireo/tagify文件夹,并打开package.json**文件。

有一个 "main"键告诉我们哪个是这个库的主文件,在这个例子中是"./dist/tagify.min.js",让我们打开它。
如果我们在tagify.min.js文件中搜索关键词 "export",应该至少有一个匹配的。

Javascript代码中的 "module.exports"会将库的功能作为模块导出,大多数现代Javascript库都会有这一行。
现在让我们回头看看有问题的'appear'包,导航到node_modules/appear/package.json并打开它。

"main "键指的是 "appear.js",它实际上位于dist/appear.js中。让我们打开这个文件,搜索关键词 "export"。

结果发现在这个库中没有导出关键词!由于它的功能没有被导出,所以我们不能导入它,这就是为什么 "import 'appear';"这行不起作用。
为了解决这个问题,我们可以使用 "require "语句来代替import,通常需要的文件在package.json的 "main "键中提到,在这个例子中是 "appear.js "文件。
在你的app/javascript/packs/application.js文件中。
import "@yaireo/tagify";
// change the import to require
// import "appear";
require("appear/dist/appear");
import "bootstrap";
import "chart.js";
注意:对于javascript文件,我们可以跳过".js "扩展名,require("appear/dist/appear") ,相当于require("appear/dist/appear.js") 。但对于CSS,我们必须添加".css "扩展名。
保存它,并在网页浏览器中刷新你的页面,它现在就可以工作了!
如果你发现自己在安装NPM包和导入它们之后,遇到了 "找不到模块 "的错误,你可以尝试把有问题的包的 "import "改为 "require"。
也可能有一些软件包在package.json文件中没有指定 "main "键,在这种情况下,你必须搜索该库的javascript文件路径,然后像这样导入或要求全路径。
// there's no "main" key specified in package.json, you have to import the full path to the actual javascript file
// import pwstrength-bootstrap
import "pwstrength-bootstrap/dist/pwstrength-bootstrap.min";
// there's no "main" key specified in package.json, and the javascript file doesn't export as module, we have to use require
require("table-edits/build/table-edits.min");
在某些情况下,导入的库实际上只是CSS,你必须导入CSS文件的完整路径:
import "flag-icon-css/css/flag-icon.min.css"
也可能有一些Javascript包带有它们自己的CSS文件,我们也必须导入这些文件,这样才会有风格。例如,daterangepicker、flatpickr和select2这些包都有自己的CSS文件,我们也需要导入它们:
/* app/javascript/packs/application.js */
// ...
import "daterangepicker";
import "daterangepicker/daterangepicker.css";
import "flatpickr";
import "flatpickr/dist/flatpickr.min.css";
import "select2";
import "select2/dist/css/select2.min.css";
"我怎么知道哪个库有自己的CSS文件?",我听到了,我也问了同样的问题,我不是Javascript专家,当我看到HTML页面上的下拉菜单表现得很奇怪时,我才意识到我需要导入这些CSS,对此我没有简单的答案。
对于daterangepicker,他们的入门部分有一个样式表包含,因此我想我需要在application.js中也导入CSS。

如果你的Javascript组件的行为或外观很奇怪,很可能它们有自己的CSS,你也需要导入它们。
Bootstrap、Jquery和Popper.js
正如我在关于如何在 Rails 6 上使用 Bootstrap 和 Jquery 的指南中所述,我们需要使用 ProvidePlugin 来进行调整,以便模块能够使用其他模块的变量。
打开config/webpack/environment.js,并将 Jquery、Bootstrap 和 Popper 添加到 ProvidePlugin 中:
const { environment } = require('@rails/webpacker')
const webpack = require("webpack");
// Add an additional plugin of your choosing : ProvidePlugin
environment.plugins.prepend(
"Provide",
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
Popper: ["popper.js", "default"] // for Bootstrap 4
})
);
environment.loaders.get('sass').use.splice(-1, 0, {
loader: 'resolve-url-loader'
})
module.exports = environment
安装自定义(专有)的 Javascript 库
对于NPM上没有的自定义库,我通常会在app/javascript中创建一个名为 "vendor "的文件夹,这样就有了完整的路径app/javascript/vendor。
复制粘贴自定义库到app/javascript/vendor文件夹中。

然后在app/javascript/packs/application.js中导入或要求这些库,使用实际Javascript文件的全路径。
如果该库已将自己导出为模块,则使用'import'(在该库的javascript文件中搜索 "export",如果没有找到,则使用require),如果该库没有将自己导出为模块,则使用'require'。
有些库可能有自己的CSS文件,记得也要导入这些CSS文件。
下面是一个导入这些供应商Javascript文件的简短例子。
// app/javascript/packs/application.js
// ....
import "../vendor/babel-polyfill/polyfill.min"
import "../vendor/chart.js.extensions/chartjs-extensions"
import "../vendor/hs-add-field/dist/hs-add-field.min"
import "../vendor/hs-count-characters/dist/js/hs-count-characters"
import "../vendor/hs-counter/dist/hs-counter.min"
import "../vendor/hs-file-attach/dist/hs-file-attach.min"
import "../vendor/hs-form-search/dist/hs-form-search.min"
import "../vendor/hs-fullscreen/dist/hs-fullscreen.min.css"
import "../vendor/hs-fullscreen/dist/hs-fullscreen.min"
import "../vendor/hs-go-to/dist/hs-go-to.min"
import "../vendor/hs-loading-state/dist/hs-loading-state.min"
import "../vendor/hs-loading-state/dist/hs-loading-state.min.css"
import "../vendor/hs-mega-menu/dist/hs-mega-menu.min.css"
import "../vendor/hs-mega-menu/dist/hs-mega-menu.min"
// ...
".../"意味着从packs文件夹往上走一级,到 "javascript "文件夹,然后".../vendor"将从 "javascript "文件夹访问vendor文件夹。
如果你遇到 "找不到模块 "的错误,记得检查库的javascript代码中是否有 "export "关键字。如果其中没有 "export "关键字,请尝试对该库使用 "require"。
可能还有一些特定主题的javscript文件,我通常把它们放在app/javascript/src文件夹下,像这样。

然后在app/javascript/packs/application.js文件中也导入它们。
// app/javascript/packs/application.js
// ...
import "../src/theme-custom";
import "../src/theme.min";
import "../src/hs.chartjs-matrix"
我们现在已经完成了javascript库的工作,接下来我们将研究复制CSS文件和图片的问题。
复制CSS和图片
本教程将使用Webpack来处理CSS和图片,如果你喜欢使用Asset Pipeline,那也可以,但本教程将不涉及。
将CSS和图片文件夹复制到app/javascript文件夹中,像这样。

然后在app/javascript/css文件夹中创建一个 "application.scss"文件(或任何你的CSS文件夹的名称,可以是 "样式表 "等)。
在application.scss文件中,导入css文件夹中的所有CSS文件。
/* app/javascript/css/application.scss */
@import "docs.min";
@import "theme.min";
接下来,前往app/javascript/packs/application.js,并导入application.scss文件以及img和svg文件夹。
/* app/javascript/packs/application.js */
// import the application.scss we created for the CSS
import "../css/application.scss";
// copy all static images under ../img and ../svg to the output folder,
// and you can reference them with <%= image_pack_tag 'media/img/abc.png' %> or <%= image_pack_tag 'media/svg/def.svg' %>
const images = require.context('../img', true)
const imagePath = (name) => images(name, true)
const svgs = require.context('../svg', true)
const svgPath = (name) => svgs(name, true)
// ...
上面的代码将允许你使用stylesheet_pack_tag来引用和加载application.scss,并使用image_pack_tag来使用图片。
接下来,前往app/views/layouts/application.html.erb,并包含styleheet pack标签,以便为所有布局加载自定义CSS文件。
PaidTemplate
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= yield %>
接下来,我们将转到HTML文件。
复制HTML文件
在本教程中,我将只复制一个HTML文件,但对于你的主题中的所有HTML文件,步骤应该是相似的。
我从我购买的主题中挑选了 "apps-invoice-generator.html "页面,我创建了一个名为invoice_generator.html.erb的新视图,并把它放在我创建的 "静态 "控制器下。
复制粘贴模板HTML的and标签之间的所有内容到这个视图。
运行rails s 和./bin/webpack-dev-server ,并导航到localhost来查看你的页面!
p/s: 如果你看到一个错误说**没有找到模块。错误。不能解决'resolve-url-loader',**你可以通过简单安装这个包来解决:
yarn add resolve-url-loader
乍一看,这个页面看起来不错!只是缺少一些图片:

只是有些图片不见了,因为原来的主题使用的是图片文件夹的相对路径,我们必须把它们改为使用image_pack_tag。
例如,这个svg标志图片标签。
我们要把它改成这个 。
<%= image_pack_tag "media/svg/logos/logo.svg", class: 'navbar-brand-logo', alt: 'Logo' %>
比方说,一个图片位于app/javascript/img/160x160/img2.jpg

然后我们可以把 "app/javascript "改为 "media",用于image_pack_tag。
<%= image_pack_tag "media/img/160x160/img2.jpg", class: 'avatar avatar-xs avatar-circle mr-2', alt: 'avatar' %>
替换完所有的图像标签后,你就差不多可以了!
调试Javascript问题
当我点击的时候,下拉菜单不工作,滑动菜单也不工作,也许有什么Javascript问题我错过了?
右键点击网页,选择 "检查元素"(如果你使用的是Chrome浏览器,则为 "检查"),然后导航到控制台选项卡,出现了 "未发现的引用错误:$未定义"的错误!这是什么原因?


这是因为HTML包含