我正在尝试根据环境切换sass导入URL。我已经审查了许多其他问题和答案,这一直困扰着我。 @import不允许使用动态字符串,因此我尝试根据环境变量对每个字符串和@ if / @ else使用mixin,但是我无法从其他sass文件访问根环境变量。
webpack.config.js
const scssRule = config.module.rules.find(rule => rule.test.test(".scss"));
const scssLoaderConfig = scssRule.use.find(({loader}) => loader === "sass-loader");
scssLoaderConfig.options = scssLoaderConfig.options || {};
scssLoaderConfig.options["implementation"] = require("sass"); //dart-sass
scssLoaderConfig.options["additionalData"] = `$env:"${env}";`; //Pass env to sass
theme.scss
//NOTE: This $env line is not actually in the file. It gets injected by webpack via sass-loader additionalData
$env: "preprod";
@forward "icons" as icon_*;
//More @forward directives such as colors
_icons.scss
@mixin importIconsPreprod {
@import "https://preprod.example.com/icons.css";
}
@mixin importIconsProd {
@import "https://example.com/icons.css";
}
@mixin importIcons() {
//SassError: Undefined variable.
@if $env == "preprod" {
@include importIconsPreprod;
} @else {
@include importIconsProd;
}
//More styles here
}
所需的实现
@use "theme-package" as theme;
//Import icons from theme.icon namespace
@include theme.icon_importIcons;
答案 0 :(得分:0)
一段时间后,我找到了解决方案。我最终生成了_env.scss文件作为webpack的一部分。此文件包含指示环境的$ env sass变量,并由_icons.scss加载。下面的代码:
webpack.config.js
const writeEnvScss = require("./scripts/write-env-scss.js");
//Write _env.scss, default to "prod"
writeEnvScss("./packages/Theme/src/Component/includes/_env.scss", "prod");
_env.scss作为构建的一部分生成的
$env:"preprod";
_icons.scss
//"env" file is created as part of webpack.config.js
@use "includes/env" as *;
@mixin importIconsPreprod {
@import "https://preprod.example.com/icons.css";
}
@mixin importIconsProd {
@import "https://example.com/icons.css";
}
@mixin importIcons() {
@if $env == "preprod" {
@include importIconsPreprod;
} @else {
@include importIconsProd;
}
}
write-env-scss.js
const fs = require("fs");
const path = require("path");
//looks for optional --env cli param or NODE_ENV environment variable
module.exports = function(scssPath, envDefault) {
scssPath = scssPath || null;
if (!scssPath) {
throw new Error("scss path required");
}
envDefault = envDefault || "local";
//Determine env
let env = getArg("--env") || process.env.NODE_ENV || null;
switch (env) {
case "development":
case "local":
env = "local";
break;
case "preprod":
break;
case "production":
case "prod":
env = "prod";
break;
default:
env = envDefault;
break;
}
console.log("ENV =>", env);
//Write _env.scss to Theme
fs.writeFileSync(path.resolve(scssPath), `$env:"${env}";`);
};
function getArg(key) {
var index = process.argv.indexOf(key);
var next = process.argv[index + 1];
return index < 0 ? null : !next || next[0] === "-" ? true : next;
}
答案 1 :(得分:0)
在我的项目(跨浏览器扩展)中,我正在使用node-sass config中的includePaths
选项来实现类似的目的。
通常,includePaths
扩展了可以导入scss模块以正确编译的文件夹范围。由于它是js API,因此您可以通过变量动态设置此路径。
这是我的操作方式示例(我使用gulp
和gulp-sass
,但它与webpack的工作方式相同。示例得到了简化,并且没有节点的“路径”):< / p>
styles
|-- firefox
| |-- _vars.scss
|
|-- chrome
| |-- _vars.scss
|
|-- styles.scss // main file
|-- gulpfile.js // builder
|-- build
styles.scss
:@import "vars";
gulpfile.js
const { src, dest } = require('gulp');
const sass = require('gulp-sass');
function styles(browser){
const srcPath = "*.scss";
const destPath = "build";
return src(srcPath)
.pipe(sass({ includePaths: browser }))
.pipe(dest(destPath))
}
gulp.default = function(){
const varDirname = "firefox"; // or "chrome"
styles(varDirname);
}
请注意,在includePaths
中仅包含文件所在的目录名称,而不要像browser/*.scss
这样的全局名称,这一点很重要。