tailwind 3 在 rails + shakapacker + HAML (webpacker@v6、webpack@v5、postcss@v8) 中无法完全加载
更新 2021-09-08:TL;DR。 Tailwind 未应用于 HAML 模板。
将项目迁移到
shakapacker
,它在后台使用
webpack@v6
和
postcss
。除了 TailwindCSS,所有其他前端 CSS 资源似乎都已正确加载。
为了简化调试,我从主文件中删除了除 Tailwind 之外的所有其他 CSS 导入。我还创建了以下测试 HTML 页面,以查看是否应用了 Tailwind CSS 样式。
test.html
...
<div class="max-w-sm rounded overflow-hidden shadow-lg">
<div class="px-6 py-4">
<div class="font-bold text-xl mb-2">
The Coldest Sunset
</div>
<p class="text-gray-700 text-base">
Lorem ipsum
</p>
</div>
</div>
...
当我查看此页面时,它看起来很简单,只有文本 - 没有应用阴影、填充、字体粗细等。当我查看生成的 CSS 输出时,似乎只加载了 Tailwind 的重置样式,没有其他内容。
您可以在此处查看输出: http://codebin.org/view/bba03ee2 。
更新时间:2022-AUG-11
根据以下评论的建议,我运行了
yarn run tailwindcss -i ./app/assets/packs/styles/application.scss -o ./output.css
,它产生了以下错误:
.../app/assets/packs/styles/application.scss:4:1: Unknown word
You tried to parse SCSS with the standard CSS parser; try again with the postcss-scss parser
该错误指向第一个注释掉的行:
// @tailwind "base";
,这是有道理的,因为
// 双正斜杠注释
是
SASS/SCSS
功能,而不是标准
CSS
。
但是,我认为包括
sass
和
sass-loader
会根据
shakapacker
安装说明处理此问题。
因此,我在
webpack.config.js
中明确指定了加载器(见下文),但错误仍然存​​在。
我已在下面包含了所有相关文件。
配置文件
application.scss
(导入所有 CSS 资产):
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
// @tailwind "base";
// @tailwind "components";
// @tailwind "utilities";
使用
@import
或
@tailwind
会产生相同的结果。
application.js
(导入
application.scss
)
我只包含了相关的代码行。
...
import "./styles/application.scss"
...
packages.json
{
"name": "app",
"private": true,
"dependencies": {
"@babel/core": "7",
"@babel/plugin-transform-runtime": "7",
"@babel/preset-env": "7",
"@babel/runtime": "7",
"@rails/actioncable": "^7.0.3-1",
"@rails/activestorage": "^7.0.3-1",
"@rails/ujs": "^7.0.3-1",
"babel-loader": "8",
"coffee-loader": "^4.0.0",
"coffeescript": "^2.7.0",
"compression-webpack-plugin": "9",
"jquery": "^3.6.0",
"jquery-ujs": "^1.2.3",
"moment": "^2.29.4",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-loader": "^7.0.1",
"postcss-preset-env": "^7.7.2",
"select2": "^4.1.0-rc.0",
"shakapacker": "6.5.0",
"tailwindcss": "^3.1.8",
"terser-webpack-plugin": "5",
"tributejs": "^5.1.3",
"turbolinks": "^5.2.0",
"webpack": "5",
"webpack-assets-manifest": "5",
"webpack-cli": "4",
"webpack-dev-server": "^4.9.3",
"webpack-merge": "5"
},
"version": "0.1.0",
"babel": {
"presets": [
"./node_modules/shakapacker/package/babel/preset.js"
]
},
"browserslist": [
"defaults"
],
"devDependencies": {
"autoprefixer": "^10.4.8",
"css-loader": "^6.7.1",
"mini-css-extract-plugin": "^2.6.1",
"postcss": "^8.4.16",
"sass": "^1.54.3",
"sass-loader": "^13.0.2",
"style-loader": "^3.3.1",
"tailwindcss": "^3.1.8"
}
}
webpack.config.js
:
const { webpackConfig, merge } = require('shakapacker')
// See the shakacode/shakapacker README and docs directory for advice on customizing your webpackConfig.
const sassLoaderConfig = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
"style-loader",
// Translates CSS into CommonJS
"css-loader",
// Compiles Sass to CSS
"sass-loader",
],
},
],
},
};
const options = {
resolve: {
extensions: ['.mjs', '.js', '.sass', ".scss", ".css", ".module.sass", ".module.scss", ".module.css", ".png", ".svg", ".gif", ".jpeg", ".jpg"]
}
}
module.exports = merge(webpackConfig, sassLoaderConfig, options);
postcss.config.js
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
})
]
}
tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./app/**/*.html',
'./app/**/*.html.slim',
'./app/**/*.html.erb',
'./app/**/*.js'
],
theme: {
extend: {},
},
plugins: [],
}
webpacker.yml
# Note: You must restart bin/webpacker-dev-server for changes to take effect
default: &default
source_path: app/assets
# You can have a subdirectory of the source_path, like 'packs' (recommended).
# Alternatively, you can use '/' to use the whole source_path directory.
source_entry_path: /packs
# If nested_entries is true, then we'll pick up subdirectories within the source_entry_path.
# You cannot set this option to true if you set source_entry_path to '/'
nested_entries: true
public_root_path: public
public_output_path: packs
cache_path: tmp/webpacker
webpack_compile_output: true
# See https://github.com/shakacode/shakapacker#deployment
webpacker_precompile: true
# Location for manifest.json, defaults to {public_output_path}/manifest.json if unset
# manifest_path: public/packs/manifest.json
# Additional paths webpack should look up modules
# ['app/assets', 'engine/foo/app/assets']
additional_paths: []
# Reload manifest.json on all requests so we reload latest compiled packs
cache_manifest: false
# Select loader to use, available options are 'babel' (default), 'swc' or 'esbuild'
webpack_loader: 'babel'
# Set to true to enable check for matching versions of shakapacker gem and NPM package - will raise an error if there is a mismatch or wildcard versioning is used
ensure_consistent_versioning: false
# Select whether the compiler will use SHA digest ('digest' option) or most most recent modified timestamp ('mtime') to determine freshness
compiler_strategy: digest
extract_css: true
development:
<<: *default
compile: true
compiler_strategy: mtime
# Reference: https://webpack.js.org/configuration/dev-server/
dev_server:
https: false
host: localhost
port: 3035
# Hot Module Replacement updates modules while the application is running without a full reload
hmr: false
# If HMR is on, CSS will by inlined by delivering it as part of the script payload via style-loader. Be sure
# that you add style-loader to your project dependencies.
#
# If you want to instead deliver CSS via <link> with the mini-extract-css-plugin, set inline_css to false.
# In that case, style-loader is not needed as a dependency.
#
# mini-extract-css-plugin is a required dependency in both cases.
inline_css: true
# Defaults to the inverse of hmr. Uncomment to manually set this.
# live_reload: true
client:
# Should we show a full-screen overlay in the browser when there are compiler errors or warnings?
overlay: true
# May also be a string
# webSocketURL:
# hostname: "0.0.0.0"
# pathname: "/ws"
# port: 8080
# Should we use gzip compression?
compress: true
# Note that apps that do not check the host are vulnerable to DNS rebinding attacks
allowed_hosts: "all"
pretty: true
headers:
'Access-Control-Allow-Origin': '*'
static:
watch:
ignored: '**/node_modules/**'
test:
<<: *default
compile: true
# Compile test packs to a separate directory
public_output_path: packs-test
production:
<<: *default
# Production depends on precompilation of packs prior to booting for performance.
compile: false
# Cache manifest.json for performance
cache_manifest: true
我能做的最好的就是解释我所知道的内容,也许有些东西会推动您朝着正确的方向前进。
$ rails _6.1.6.1_ new shaka --skip-javascript
$ cd shaka
# https://github.com/shakacode/shakapacker#installation
$ bin/bundle add shakapacker
$ bin/rails webpacker:install
# https://tailwindcss.com/docs/installation
$ bin/yarn add tailwindcss
$ bin/yarn tailwindcss init
$ bin/rails g controller Home index
更新一些文件,以便我们可以测试所有内容:
// app/views/home/index.html.erb
<h1 class="text-red-500">Am I red?</h1>
// app/views/layouts/application.html.erb
// only need the asset pipline, for now
<%= stylesheet_link_tag "tailwind.bundle" %>
// tailwind.config.js
// update content to include views
content: [ "./app/views/**/*.html.erb" ],
// alternatively, since we need all the views anyway, just get them all,
// it'll grab a few unneeded files, like .jbuilder, no big deal:
// content: [ "./app/views/**/*" ],
// app/javascript/styles/tailwind.css
@tailwind utilities;
目前
tailwindcss
尚未集成到
shakapacker
、
webpack
或
sass
中。我们可以运行
tailwindcss
命令来编译我们的样式并让
sprockets
为它们提供服务。
$ bin/yarn tailwindcss -i ./app/javascript/styles/tailwind.css -o ./app/assets/stylesheets/tailwind.bundle.css --watch
# start the server and open http://localhost:3000/home/index
$ bin/rails s
# you should see a red title
您也可以
@import
其他文件(内部使用
postcss-import
):
// app/javascript/styles/tailwind.css
@import "./imported.css";
@tailwind utilities;
// app/javascript/styles/imported.css
h1 { background-color: yellow; }
这是
tailwindcss
自行执行的操作(
v3.1.8
)。通过覆盖
postcss
配置可以添加其他功能。
https://tailwindcss.com/docs/using-with-preprocessors#using-post-css-as-your-preprocessor
// postcss.config.js
module.exports = {
plugins: {
"postcss-import": {}, // process @import
"tailwindcss/nesting": {}, // add sass like nesting
tailwindcss: {}, // then let tailwind do its thing
}
}
// app/javascript/styles/imported.css
body {
h1 {
background-color: green;
}
}
使用
--postcss
标志覆盖
postcss
配置:
$ bin/yarn tailwindcss --postcss postcss.config.js -i ./app/javascript/styles/tailwind.css -o ./app/assets/stylesheets/tailwind.bundle.css --watch
顺便说一句,这就是 cssbundling-rails 的操作方式。如果您需要通过 webpack 导入 css,则需要更改一些内容。
// app/javascript/application.js
import "./styles/tailwind.css"
如果您尝试运行
bin/webpack-dev-server
,您将获得:
ERROR in ./app/javascript/styles/tailwind.css 1:0
Module parse failed: Unexpected character '@' (1:0)
Webpack 不知道如何处理 css。添加 css 加载器:
$ bin/yarn add css-loader mini-css-extract-plugin
将样式表包添加到布局:
# app/views/layouts/application.html.erb
# don't need this
# stylesheet_link_tag "application", "tailwind.bundle", media: "all"
<%= javascript_pack_tag "application" %>
<%= stylesheet_pack_tag "application" %>
启动
bin/webpack-dev-server
,您应该获得相同的结果红色/绿色标题。如果您查看生成的 css 文件:
/*!****************************************************************************************************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[2].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[2].use[2]!./app/javascript/styles/tailwind.css ***!
\****************************************************************************************************************************************************************************************/
body h1 { background-color: green; }
.inline { display: inline; }
.text-red-500 { --tw-text-opacity: 1; color: rgb(239 68 68 / var(--tw-text-opacity)); }
/*# sourceMappingURL=application.css.map*/
顶部的注释显示
tailwind.css
由
postcss-loader
处理,然后由
css-loader
处理。
https://webpack.js.org/concepts/loaders#configuration
我们知道我们的 postcss 配置正在运行,它已连接 tailwindcss 、 tailwindcss/nesting 和 postcss-import 。因此,您会得到相同的结果。
如果您必须使用
sass
,只需将其放在顶部,一切仍然应该正常工作。首先,将每个
css
重命名为
scss
。您应该会收到来自
webpack
的错误,因为它不知道如何处理
scss
。所以我们需要 sass 加载器:
$ bin/yarn add sass-loader sass
Sass 会执行 @import 和嵌套,因此不再需要这些:
"postcss-import": {},
"tailwindcss/nesting": {},
在
sass
完成后,剩下要做的就是处理
@tailwind
、
@layer
、
@apply
和其他
tailwind
指令。
// postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
}
}
这就是我所知道的一切。此外,我根本没有触碰任何
webpack
配置,
shakapacker
会
自动
完成大部分配置。我尝试使用
assets/packs
目录,结果相同。注意导入的顺序:
https://tailwindcss.com/docs/using-with-preprocessors#build-time-imports
我不确定谁在这个堆栈中执行导入,应该是 sass 。尽管 css-loader 也知道如何 @import 。如果你离开 postcss-import ,它也知道如何 @import 。我敢打赌他们每个人都会以不同的方式做到这一点。
我跳过的东西:
autoprefixer
、
style-loader
、
css-minimizer-webpack-plugin
。
所以,经过一番搜寻,罪魁祸首就在
tailwind.config.js
文件中。我没有提到我正在使用
HAML
模板,并且我忘记将
*.haml
扩展添加到 tailwind 配置中。
我将更新原始问题,以便将 HAML 作为问题的一部分。
解决方案如下。
const plugin = require('tailwindcss/plugin')
module.exports = {
content: [
...
'./app/views/**/*.html.haml',
'./app/views/**/*.haml',
...
],
plugins: [
...
]
}