Angular:如何将JSON变量解析为SCSS
Angular: How to parse JSON variables into SCSS
在 Angular 应用程序中,我通过任一普通 D3 or Vega 制作 D3 视觉效果。还有 SCSS 样式正在进行中。
我希望能够从 Javascript 和 SCSS 引用相同的全局变量来进行样式设置。 JSON 文件可以很好地存储我通过简单的 import
语句加载到 Typescript 中的设置。但是如何从 SCSS 做同样的事情呢?
node-sass-json-importer
似乎是一个不错的候选者,但将其添加到 Angular 9 CLI 应用程序对我来说并不明显。
This Whosebug post前段时间刷过这个话题,但是涉及到修改node_modules
下的资源,很难持续。
原始文档中也有一些关于 how one can go about tweaking webpack in a non-Angular app 的输入。我不知道如何将它与通过 CLI 构建的 Angular 应用联系起来。
Webpack / sass-loader
Blockquote
Webpack v1
import jsonImporter from 'node-sass-json-importer';
// Webpack config
export default {
module: {
loaders: [{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}],
},
// Apply the JSON importer via sass-loader's options.
sassLoader: {
importer: jsonImporter()
}
};
Webpack v2
import jsonImporter from 'node-sass-json-importer';
// Webpack config
export default {
module: {
rules: [
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1
},
},
{
loader: 'sass-loader',
// Apply the JSON importer via sass-loader's options.
options: {
importer: jsonImporter(),
},
},
],
],
},
};
您可以在不更改任何 node_modules
文件的情况下使用 @angular-builders/custom-webpack
to setup custom Webpack rules and as you mention node-sass-json-importer
将 JSON 文件导入 SCSS 文件。
您必须安装 node-sass
for the implementation
option because node-sass-json-importer
is compatible with node-sass
。
安装包@angular-builders/custom-webpack
, node-sass-json-importer
and node-sass
:
npm i -D @angular-builders/custom-webpack node-sass-json-importer node-sass
创建Webpack配置文件(webpack.config.js
)到项目根目录,内容如下:
const jsonImporter = require('node-sass-json-importer');
module.exports = {
module: {
rules: [{
test: /\.scss$|\.sass$/,
use: [
{
loader: require.resolve('sass-loader'),
options: {
implementation: require('node-sass'),
sassOptions: {
// bootstrap-sass requires a minimum precision of 8
precision: 8,
importer: jsonImporter(),
outputStyle: 'expanded'
}
},
}
],
}],
},
}
将 builder
更改为 @angular-builders/custom-webpack:[architect-target]
并将 customWebpackConfig
选项添加到 build
、serve
和 test
构建目标里面 angular.json
:
"projects": {
...
"[project]": {
...
"architect": {
"build": {
"builder: "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "webpack.config.js"
},
...
},
...
},
"serve": {
"builder: "@angular-builders/custom-webpack:dev-server",
"customWebpackConfig": {
"path": "webpack.config.js"
},
...
},
"test": {
"builder: "@angular-builders/custom-webpack:karma",
"customWebpackConfig": {
"path": "webpack.config.js"
},
...
},
},
...
},
...
}
现在您可以在任何组件 .scss
文件中包含任何 .json
文件:
hello-world.component.scss
:
@import 'hello-world.vars.json';
.hello-bg {
padding: 20px;
background-color: $bg-color;
border: 2px solid $border-color;
}
hello-world.vars.json
:
{
"bg-color": "yellow",
"border-color": "red"
}
我创建了一个 Github 存储库,您可以从这里克隆和测试所有这些工作:https://github.com/clytras/angular-json-scss
git clone https://github.com/clytras/angular-json-scss.git
cd angular-json-scss
npm install
ng serve
我有一个比较简单的方法给你:
将 node-sass
步骤与 ng build
步骤分开,并使用生成的 .css
文件代替 angular 应用中的 sass
文件。
这有两个好处:
- 无需大量调整和编辑任何节点模块
- 完全控制 sass 的编译方式
对于实施,我将按如下方式进行:
- 将
./node_modules/.bin/node-sass --importer node_modules/node-sass-json-importer/dist/cli.js --recursive ./src --output ./src
添加到 package.json
中的脚本,例如名字 build-sass
。您可以调整此命令以仅包含需要递归模式的 sass 文件(确保在 angular.json 中忽略它们,这样它们就不会被编译两次)。
- 运行 命令一次
npm run build-sass
以便在项目中生成.css
个文件。
- 将 angular 组件中需要的引用从
.sass
更改为 .css
- (可选)在您的 package.json 中添加一个方便的命令
npm run build-sass && ng build
作为 compile
,您可以随时 运行 构建整个项目。
虽然这种方法相对简单,但也有一些缺点
- 对于您要使用 css 的任何组件,
ng serve
的热重载功能将要求您 运行 您的 npm run build-sass
以查看任何更改你实时制作了你的风格
- 您的项目看起来会有点乱,因为在生成
.css
的 /src
文件夹中有相同组件的 .scss
和 .css
文件.您需要确保(例如通过添加后缀或注释)没有人意外编辑生成的 .css
并且这些更改会被覆盖。
其他方法几乎总是涉及大量编辑现有的或编写您自己的 webpack 编译器。
另一种选择是使用 raw-loader
,它在 angular-cli 中默认可用。这样你就可以将原始 scss 文件加载到 ts 组件中:
// Adding `!!` to a request will disable all loaders specified in the configuration
import scss from '!!raw-loader!./config.scss';
console.info('scss', scss);
您必须在 .d.ts
文件中声明模块:
declare module '!!raw-loader!./*.scss';
然后您可以提取任何您想要的信息。
因此,您可以将 scss 加载到 ts 中,而不是将 JSON 加载到 scss 中。
工作于 angular 10:
正如其他人提到的那样使用自定义 webpack,但我在 angular 10 中唯一可行的方法是编辑一个函数,最初由 Kishorevarma.
建议
webpack.config.js
const jsonImporter = require("node-sass-json-importer");
const webpack = require("webpack");
const mode =
process.env.NODE_ENV === "production" ? "production" : "development";
module.exports = function (config) {
const rules = config.module.rules || [];
rules.forEach((rule) => {
if (String(rule.test) === String(/\.scss$|\.sass$/)) {
const loaders = rule.use;
const transformedLoaders = loaders.map((l) => {
if (l.loader && l.loader.search("sass-loader") !== -1) {
l.options.sassOptions.importer = jsonImporter();
}
return l;
});
rule.use = transformedLoaders;
}
});
return config;
};
我一直在导入最初为 angular flexlayout 创建的断点。
breakpoints.json
{
"breakpoints": [
{
"alias": "xs",
// Notice the quoting
"mediaQuery": "'screen and (min-width: 0px) and (max-width: 599.98px)'",
"priority": 1000
},
...
]
}
breakpoints.scss
@import "./breakpoints.json";
$bps: ();
// Reformat from json
@each $breakpoint in $breakpoints {
$i: index($breakpoints, $breakpoint);
$bps: map-merge(
$bps,
(
map-get($breakpoint, alias): map-get($breakpoint, mediaQuery),
)
);
}
// Can be used with
// @media #{(map-get($bps, xs))} {
// margin: 0 -15px;
// }
breakpoints.ts
import { BreakPoint } from '@angular/flex-layout';
// Custom breakpoints
const brkpnts: BreakPoint[] = require('./breakpoints.json').breakpoints;
export const JSONBreakpoints = brkpnts.map((bp) => {
// Remove the single qoutes needed for the sass variables
return { ...bp, mediaQuery: bp.mediaQuery.substring(1).slice(0, -1) };
});
app.module.ts
import { JSONBreakpoints } from './breakpoints';
@NgModule({
imports: [
FlexLayoutModule.withConfig({ disableDefaultBps: true }, JSONBreakpoints)
]
})
在 Angular 应用程序中,我通过任一普通 D3 or Vega 制作 D3 视觉效果。还有 SCSS 样式正在进行中。
我希望能够从 Javascript 和 SCSS 引用相同的全局变量来进行样式设置。 JSON 文件可以很好地存储我通过简单的 import
语句加载到 Typescript 中的设置。但是如何从 SCSS 做同样的事情呢?
node-sass-json-importer
似乎是一个不错的候选者,但将其添加到 Angular 9 CLI 应用程序对我来说并不明显。
This Whosebug post前段时间刷过这个话题,但是涉及到修改node_modules
下的资源,很难持续。
原始文档中也有一些关于 how one can go about tweaking webpack in a non-Angular app 的输入。我不知道如何将它与通过 CLI 构建的 Angular 应用联系起来。
Webpack / sass-loader Blockquote
Webpack v1
import jsonImporter from 'node-sass-json-importer';
// Webpack config
export default {
module: {
loaders: [{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}],
},
// Apply the JSON importer via sass-loader's options.
sassLoader: {
importer: jsonImporter()
}
};
Webpack v2
import jsonImporter from 'node-sass-json-importer';
// Webpack config
export default {
module: {
rules: [
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1
},
},
{
loader: 'sass-loader',
// Apply the JSON importer via sass-loader's options.
options: {
importer: jsonImporter(),
},
},
],
],
},
};
您可以在不更改任何 node_modules
文件的情况下使用 @angular-builders/custom-webpack
to setup custom Webpack rules and as you mention node-sass-json-importer
将 JSON 文件导入 SCSS 文件。
您必须安装 node-sass
for the implementation
option because node-sass-json-importer
is compatible with node-sass
。
安装包
@angular-builders/custom-webpack
,node-sass-json-importer
andnode-sass
:npm i -D @angular-builders/custom-webpack node-sass-json-importer node-sass
创建Webpack配置文件(
webpack.config.js
)到项目根目录,内容如下:const jsonImporter = require('node-sass-json-importer'); module.exports = { module: { rules: [{ test: /\.scss$|\.sass$/, use: [ { loader: require.resolve('sass-loader'), options: { implementation: require('node-sass'), sassOptions: { // bootstrap-sass requires a minimum precision of 8 precision: 8, importer: jsonImporter(), outputStyle: 'expanded' } }, } ], }], }, }
将
builder
更改为@angular-builders/custom-webpack:[architect-target]
并将customWebpackConfig
选项添加到build
、serve
和test
构建目标里面angular.json
:"projects": { ... "[project]": { ... "architect": { "build": { "builder: "@angular-builders/custom-webpack:browser", "options": { "customWebpackConfig": { "path": "webpack.config.js" }, ... }, ... }, "serve": { "builder: "@angular-builders/custom-webpack:dev-server", "customWebpackConfig": { "path": "webpack.config.js" }, ... }, "test": { "builder: "@angular-builders/custom-webpack:karma", "customWebpackConfig": { "path": "webpack.config.js" }, ... }, }, ... }, ... }
现在您可以在任何组件 .scss
文件中包含任何 .json
文件:
hello-world.component.scss
:
@import 'hello-world.vars.json';
.hello-bg {
padding: 20px;
background-color: $bg-color;
border: 2px solid $border-color;
}
hello-world.vars.json
:
{
"bg-color": "yellow",
"border-color": "red"
}
我创建了一个 Github 存储库,您可以从这里克隆和测试所有这些工作:https://github.com/clytras/angular-json-scss
git clone https://github.com/clytras/angular-json-scss.git
cd angular-json-scss
npm install
ng serve
我有一个比较简单的方法给你:
将 node-sass
步骤与 ng build
步骤分开,并使用生成的 .css
文件代替 angular 应用中的 sass
文件。
这有两个好处:
- 无需大量调整和编辑任何节点模块
- 完全控制 sass 的编译方式
对于实施,我将按如下方式进行:
- 将
./node_modules/.bin/node-sass --importer node_modules/node-sass-json-importer/dist/cli.js --recursive ./src --output ./src
添加到package.json
中的脚本,例如名字build-sass
。您可以调整此命令以仅包含需要递归模式的 sass 文件(确保在 angular.json 中忽略它们,这样它们就不会被编译两次)。 - 运行 命令一次
npm run build-sass
以便在项目中生成.css
个文件。 - 将 angular 组件中需要的引用从
.sass
更改为.css
- (可选)在您的 package.json 中添加一个方便的命令
npm run build-sass && ng build
作为compile
,您可以随时 运行 构建整个项目。
虽然这种方法相对简单,但也有一些缺点
- 对于您要使用 css 的任何组件,
ng serve
的热重载功能将要求您 运行 您的npm run build-sass
以查看任何更改你实时制作了你的风格 - 您的项目看起来会有点乱,因为在生成
.css
的/src
文件夹中有相同组件的.scss
和.css
文件.您需要确保(例如通过添加后缀或注释)没有人意外编辑生成的.css
并且这些更改会被覆盖。
其他方法几乎总是涉及大量编辑现有的或编写您自己的 webpack 编译器。
另一种选择是使用 raw-loader
,它在 angular-cli 中默认可用。这样你就可以将原始 scss 文件加载到 ts 组件中:
// Adding `!!` to a request will disable all loaders specified in the configuration
import scss from '!!raw-loader!./config.scss';
console.info('scss', scss);
您必须在 .d.ts
文件中声明模块:
declare module '!!raw-loader!./*.scss';
然后您可以提取任何您想要的信息。
因此,您可以将 scss 加载到 ts 中,而不是将 JSON 加载到 scss 中。
工作于 angular 10: 正如其他人提到的那样使用自定义 webpack,但我在 angular 10 中唯一可行的方法是编辑一个函数,最初由 Kishorevarma.
建议webpack.config.js
const jsonImporter = require("node-sass-json-importer");
const webpack = require("webpack");
const mode =
process.env.NODE_ENV === "production" ? "production" : "development";
module.exports = function (config) {
const rules = config.module.rules || [];
rules.forEach((rule) => {
if (String(rule.test) === String(/\.scss$|\.sass$/)) {
const loaders = rule.use;
const transformedLoaders = loaders.map((l) => {
if (l.loader && l.loader.search("sass-loader") !== -1) {
l.options.sassOptions.importer = jsonImporter();
}
return l;
});
rule.use = transformedLoaders;
}
});
return config;
};
我一直在导入最初为 angular flexlayout 创建的断点。
breakpoints.json
{
"breakpoints": [
{
"alias": "xs",
// Notice the quoting
"mediaQuery": "'screen and (min-width: 0px) and (max-width: 599.98px)'",
"priority": 1000
},
...
]
}
breakpoints.scss
@import "./breakpoints.json";
$bps: ();
// Reformat from json
@each $breakpoint in $breakpoints {
$i: index($breakpoints, $breakpoint);
$bps: map-merge(
$bps,
(
map-get($breakpoint, alias): map-get($breakpoint, mediaQuery),
)
);
}
// Can be used with
// @media #{(map-get($bps, xs))} {
// margin: 0 -15px;
// }
breakpoints.ts
import { BreakPoint } from '@angular/flex-layout';
// Custom breakpoints
const brkpnts: BreakPoint[] = require('./breakpoints.json').breakpoints;
export const JSONBreakpoints = brkpnts.map((bp) => {
// Remove the single qoutes needed for the sass variables
return { ...bp, mediaQuery: bp.mediaQuery.substring(1).slice(0, -1) };
});
app.module.ts
import { JSONBreakpoints } from './breakpoints';
@NgModule({
imports: [
FlexLayoutModule.withConfig({ disableDefaultBps: true }, JSONBreakpoints)
]
})