使用 rails/webpacker 在 vue 应用程序中使用 vuetify 自定义 sass 变量
Using vuetify custom sass variables in a vue app using rails/webpacker
我正在开发一个带有 Rails 后端的 Vue 应用程序。我正在使用 Vuetify,我想自定义 SCSS 变量。遗憾的是,我不能使用 Vue-CLI,因为我们将所有东西都与 webpacker 捆绑在一起,webpack 的 rails 实现。因此,我尝试使用基本的 webpack 配置选项来实现它。
我无法直接执行此操作,因为 webpacker 有自己的 css/sass/scss 加载程序配置。但是,我 可以 连接到现有的加载器并修改函数中的选项,以便稍后设置它们:
// config/webpack/environment.js
const updateStyleLoaders = (arr) => {
arr.forEach((item) => {
const loader = environment.loaders.get(item);
// Use vue-style-loader instead of default to parse Vue SFCs
const styleConfig = loader.use.find((el) => el.loader === 'style-loader');
if (styleConfig !== undefined) {
styleConfig.loader = 'vue-style-loader';
}
// VUETIFY: Use Dart-Sass and Fibers for Sass loaders
const sassConfig = loader.use.find((el) => el.loader === 'sass-loader');
if (sassConfig !== undefined) {
const opts = sassConfig.options;
opts.implementation = require('sass'); // Use dart-sass instead of node-sass
opts.fiber = require('fibers'); // improves compilation speed
opts.data = "@import '@/assets/sass/variables.scss';"; // Import custom variables
}
});
};
// Call fuction for all css-related loaders
updateStyleLoaders(['sass', 'css', 'moduleCss', 'moduleSass']);
// @/assets/sass/variables.scss
$body-font-family: "Comic Sans MS", "Comic Sans", cursive; // just wanna have fun
$border-radius-root: 20px;
问题来了:
sass-loader 规则同时匹配 'sass' 和 'scss'。在 vuetify's example 中, sass 和 scss 的匹配是分开完成的。当我添加分号时,我在编译过程中得到这个错误:
./node_modules/vuetify/src/components/VAlert/VAlert.sass
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
// Imports
^
Semicolons aren't allowed in the indented syntax.
╷
1 │ @import '@/assets/sass/variables.scss';
│ ^
╵
stdin 1:39 root stylesheet
这告诉我该行实际上是由 sass-loader 正确添加到添加的 vuetify 组件中。但是,当我从中删除分号 import 语句支持 sass' 缩进语法,我没有看到任何样式变化。
在这种情况下,我将如何自定义我的 vuetify 组件? Webpacker 使用 sass-loader v7.3.1.
大约 2 天前,我在尝试配置 Storybook 以在 Vue/Vuetify 项目中工作时遇到了一个非常相似的问题。非常令人沮丧。这是我的工作 webpack.config.js
文件现在的样子:
const path = require('path')
module.exports = async ({ config }) => {
config.module.rules.push({
test: /\.s(a|c)ss$/,
use: [
'style-loader',
'css-loader',
// 'sass-loader'
{
loader: 'sass-loader',
options: {
sassOptions: {
indentedSyntax: true, // <-- THIS WAS THE KEY!
},
// NOTE: NO SEMICOLON USED
prependData: `@import '${path.resolve(__dirname, '..', 'src', 'scss', 'variables.scss')}'`,
},
},
],
include: path.resolve(__dirname, '../'),
})
return config
}
我从未使用过 webpacker
但根据您发布的内容,我会尝试这样的操作:
const updateStyleLoaders = (arr) => {
arr.forEach((item) => {
const loader = environment.loaders.get(item);
// Use vue-style-loader instead of default to parse Vue SFCs
const styleConfig = loader.use.find((el) => el.loader === 'style-loader');
if (styleConfig !== undefined) {
styleConfig.loader = 'vue-style-loader';
}
// VUETIFY: Use Dart-Sass and Fibers for Sass loaders
const sassConfig = loader.use.find((el) => el.loader === 'sass-loader');
if (sassConfig !== undefined) {
const opts = sassConfig.options;
opts.implementation = require('sass'); // Use dart-sass instead of node-sass
opts.fiber = require('fibers'); // improves compilation speed
// ADD THIS LINE
opts.sassOptions.indentedSytax = true;
// OR MAYBE THIS ONE???
opts.indentedSyntax = true;
// THEN REMOVE THE SEMICOLON (or keep the semicolon and set indentedSyntax to false?)
opts.data = "@import '@/assets/sass/variables.scss'"; // Import custom variables
}
});
};
Full docs for all of the options available to sass-loader
are here。 FWIW,我发现 webpack 配置是我面临的最具挑战性的事情之一。绝对是在hard模式下玩编程!
我认为你很接近。很想知道什么配置最终解决了它。
感谢 this GitHub comment 的帮助,我已经开始工作了。
可以使用 environment.loaders.delete('sass') // same for 'moduleSass', 'moduleCss', 'css'
删除默认加载器。
然后,他们可以换成新的。我已经将 scss 和 sass 加载程序分离到它们自己的文件中:
// config/webpack/loaders/sass.js
const { config } = require('@rails/webpacker');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
test: /\.sass$/,
use: [
config.extract_css === false
? 'vue-style-loader'
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 2,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
implementation: require('sass'),
fiber: require('fibers'),
data: '@import "app/frontend/src/assets/styles/variables.scss"',
},
},
],
};
// config/webpack/loaders/scss.js
const { config } = require('@rails/webpacker');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
test: /\.scss$/,
use: [
config.extract_css === false
? 'vue-style-loader'
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 2,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
implementation: require('sass'),
fiber: require('fibers'),
data: '@import "app/frontend/src/assets/styles/variables.scss";',
},
},
],
};
这些重新实现了带有 CSS 提取的基本 webpacker 集成。
然后,我将它们添加到主配置中,如下所示:
// config/webpack/environment.js
const { environment } = require('@rails/webpacker');
const path = require('path');
// Plugins
const { VueLoaderPlugin } = require('vue-loader');
const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin');
// Loaders
const erb = require('./loaders/erb');
const sass = require('./loaders/sass');
const scss = require('./loaders/scss');
const vue = require('./loaders/vue');
const yml = require('./loaders/yml');
// Remove webpacker's conflicting loaders
environment.loaders.delete('moduleSass');
environment.loaders.delete('moduleCss');
environment.loaders.delete('sass');
// Modify base css loader to support vue SFC style tags
environment.loaders.get('css').use.find((el) => el.loader === 'style-loader').loader = 'vue-style-loader';
// Apply plugins
environment.plugins.prepend('VuetifyLoaderPlugin', new VuetifyLoaderPlugin());
environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin());
// Apply custom loaders
environment.loaders.append('erb', erb);
environment.loaders.append('yml', yml);
environment.loaders.append('vue', vue);
environment.loaders.append('sass', sass);
environment.loaders.append('scss', scss);
// Shorthands for import statements
environment.config.resolve.alias = {
// Use the same vue package everywhere
vue: 'vue/dist/vue.esm',
// use '@' as absolute path from /src
'@': path.resolve(__dirname, '../../app/frontend/src/'),
};
module.exports = environment;
这里还有一个重要的部分是我仍然修改默认的 css-loader 以使用 'vue-style-loader' 而不是 'style-loader'。但是对于更大的变化(比如 vuetify),我可以为 SASS / SCSS 语法定义我自己定义的加载器。
也许可以进一步优化以消除重复,但只要它只有两种配置,我就很高兴它能工作:)
我正在开发一个带有 Rails 后端的 Vue 应用程序。我正在使用 Vuetify,我想自定义 SCSS 变量。遗憾的是,我不能使用 Vue-CLI,因为我们将所有东西都与 webpacker 捆绑在一起,webpack 的 rails 实现。因此,我尝试使用基本的 webpack 配置选项来实现它。
我无法直接执行此操作,因为 webpacker 有自己的 css/sass/scss 加载程序配置。但是,我 可以 连接到现有的加载器并修改函数中的选项,以便稍后设置它们:
// config/webpack/environment.js
const updateStyleLoaders = (arr) => {
arr.forEach((item) => {
const loader = environment.loaders.get(item);
// Use vue-style-loader instead of default to parse Vue SFCs
const styleConfig = loader.use.find((el) => el.loader === 'style-loader');
if (styleConfig !== undefined) {
styleConfig.loader = 'vue-style-loader';
}
// VUETIFY: Use Dart-Sass and Fibers for Sass loaders
const sassConfig = loader.use.find((el) => el.loader === 'sass-loader');
if (sassConfig !== undefined) {
const opts = sassConfig.options;
opts.implementation = require('sass'); // Use dart-sass instead of node-sass
opts.fiber = require('fibers'); // improves compilation speed
opts.data = "@import '@/assets/sass/variables.scss';"; // Import custom variables
}
});
};
// Call fuction for all css-related loaders
updateStyleLoaders(['sass', 'css', 'moduleCss', 'moduleSass']);
// @/assets/sass/variables.scss
$body-font-family: "Comic Sans MS", "Comic Sans", cursive; // just wanna have fun
$border-radius-root: 20px;
问题来了:
sass-loader 规则同时匹配 'sass' 和 'scss'。在 vuetify's example 中, sass 和 scss 的匹配是分开完成的。当我添加分号时,我在编译过程中得到这个错误:
./node_modules/vuetify/src/components/VAlert/VAlert.sass
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
// Imports
^
Semicolons aren't allowed in the indented syntax.
╷
1 │ @import '@/assets/sass/variables.scss';
│ ^
╵
stdin 1:39 root stylesheet
这告诉我该行实际上是由 sass-loader 正确添加到添加的 vuetify 组件中。但是,当我从中删除分号 import 语句支持 sass' 缩进语法,我没有看到任何样式变化。
在这种情况下,我将如何自定义我的 vuetify 组件? Webpacker 使用 sass-loader v7.3.1.
大约 2 天前,我在尝试配置 Storybook 以在 Vue/Vuetify 项目中工作时遇到了一个非常相似的问题。非常令人沮丧。这是我的工作 webpack.config.js
文件现在的样子:
const path = require('path')
module.exports = async ({ config }) => {
config.module.rules.push({
test: /\.s(a|c)ss$/,
use: [
'style-loader',
'css-loader',
// 'sass-loader'
{
loader: 'sass-loader',
options: {
sassOptions: {
indentedSyntax: true, // <-- THIS WAS THE KEY!
},
// NOTE: NO SEMICOLON USED
prependData: `@import '${path.resolve(__dirname, '..', 'src', 'scss', 'variables.scss')}'`,
},
},
],
include: path.resolve(__dirname, '../'),
})
return config
}
我从未使用过 webpacker
但根据您发布的内容,我会尝试这样的操作:
const updateStyleLoaders = (arr) => {
arr.forEach((item) => {
const loader = environment.loaders.get(item);
// Use vue-style-loader instead of default to parse Vue SFCs
const styleConfig = loader.use.find((el) => el.loader === 'style-loader');
if (styleConfig !== undefined) {
styleConfig.loader = 'vue-style-loader';
}
// VUETIFY: Use Dart-Sass and Fibers for Sass loaders
const sassConfig = loader.use.find((el) => el.loader === 'sass-loader');
if (sassConfig !== undefined) {
const opts = sassConfig.options;
opts.implementation = require('sass'); // Use dart-sass instead of node-sass
opts.fiber = require('fibers'); // improves compilation speed
// ADD THIS LINE
opts.sassOptions.indentedSytax = true;
// OR MAYBE THIS ONE???
opts.indentedSyntax = true;
// THEN REMOVE THE SEMICOLON (or keep the semicolon and set indentedSyntax to false?)
opts.data = "@import '@/assets/sass/variables.scss'"; // Import custom variables
}
});
};
Full docs for all of the options available to sass-loader
are here。 FWIW,我发现 webpack 配置是我面临的最具挑战性的事情之一。绝对是在hard模式下玩编程!
我认为你很接近。很想知道什么配置最终解决了它。
感谢 this GitHub comment 的帮助,我已经开始工作了。
可以使用 environment.loaders.delete('sass') // same for 'moduleSass', 'moduleCss', 'css'
删除默认加载器。
然后,他们可以换成新的。我已经将 scss 和 sass 加载程序分离到它们自己的文件中:
// config/webpack/loaders/sass.js
const { config } = require('@rails/webpacker');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
test: /\.sass$/,
use: [
config.extract_css === false
? 'vue-style-loader'
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 2,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
implementation: require('sass'),
fiber: require('fibers'),
data: '@import "app/frontend/src/assets/styles/variables.scss"',
},
},
],
};
// config/webpack/loaders/scss.js
const { config } = require('@rails/webpacker');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
test: /\.scss$/,
use: [
config.extract_css === false
? 'vue-style-loader'
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 2,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
implementation: require('sass'),
fiber: require('fibers'),
data: '@import "app/frontend/src/assets/styles/variables.scss";',
},
},
],
};
这些重新实现了带有 CSS 提取的基本 webpacker 集成。
然后,我将它们添加到主配置中,如下所示:
// config/webpack/environment.js
const { environment } = require('@rails/webpacker');
const path = require('path');
// Plugins
const { VueLoaderPlugin } = require('vue-loader');
const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin');
// Loaders
const erb = require('./loaders/erb');
const sass = require('./loaders/sass');
const scss = require('./loaders/scss');
const vue = require('./loaders/vue');
const yml = require('./loaders/yml');
// Remove webpacker's conflicting loaders
environment.loaders.delete('moduleSass');
environment.loaders.delete('moduleCss');
environment.loaders.delete('sass');
// Modify base css loader to support vue SFC style tags
environment.loaders.get('css').use.find((el) => el.loader === 'style-loader').loader = 'vue-style-loader';
// Apply plugins
environment.plugins.prepend('VuetifyLoaderPlugin', new VuetifyLoaderPlugin());
environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin());
// Apply custom loaders
environment.loaders.append('erb', erb);
environment.loaders.append('yml', yml);
environment.loaders.append('vue', vue);
environment.loaders.append('sass', sass);
environment.loaders.append('scss', scss);
// Shorthands for import statements
environment.config.resolve.alias = {
// Use the same vue package everywhere
vue: 'vue/dist/vue.esm',
// use '@' as absolute path from /src
'@': path.resolve(__dirname, '../../app/frontend/src/'),
};
module.exports = environment;
这里还有一个重要的部分是我仍然修改默认的 css-loader 以使用 'vue-style-loader' 而不是 'style-loader'。但是对于更大的变化(比如 vuetify),我可以为 SASS / SCSS 语法定义我自己定义的加载器。
也许可以进一步优化以消除重复,但只要它只有两种配置,我就很高兴它能工作:)