【问题标题】:Angular: How to parse JSON variables into SCSSAngular:如何将 JSON 变量解析为 SCSS
【发布时间】:2020-06-16 00:59:16
【问题描述】:

在 Angular 应用程序中,我通过普通的 D3Vega 进行 D3 视觉效果。还有 SCSS 样式。

我希望能够从 Javascript 和 SCSS 引用相同的全局变量来进行样式设置。 JSON 文件可以很好地存储我通过简单的import 语句加载到 Typescript 中的设置。但是如何从 SCSS 做同样的事情呢?

node-sass-json-importer 似乎是一个不错的候选者,但将其添加到 Angular 9 CLI 应用程序对我来说并不明显。

This StackOverflow post 前段时间刷过这个话题,但涉及到修改node_modules 下的资源,这很难持续。

原始文档中也有一些关于how one can go about tweaking webpack in a non-Angular app 的输入。我不知道如何将它与通过 CLI 构建的 Angular 应用程序联系起来。

Webpack / sass-loader 块引用

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(),
          },
        },
      ],
    ],
  },
};

【问题讨论】:

标签: json angular sass angular9 node-sass-json-importer


【解决方案1】:

您可以在不更改任何 node_modules 文件的情况下执行此操作,方法是使用 @angular-builders/custom-webpack 设置自定义 Webpack 规则,并使用 node-sass-json-importer 在 SCSS 文件中导入 JSON 文件。

您必须为implementation 选项安装node-sass,因为node-sass-json-importernode-sass 兼容。

  1. 安装包@angular-builders/custom-webpacknode-sass-json-importernode-sass

    npm i -D @angular-builders/custom-webpack node-sass-json-importer node-sass
    
  2. 在项目根目录下创建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'
                }
              },
            }
          ],
        }],
      },
    }
    
  3. builder 更改为@angular-builders/custom-webpack:[architect-target] 并将customWebpackConfig 选项添加到buildservetestangular.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

【讨论】:

    【解决方案2】:

    另一个选项是使用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 中。

    【讨论】:

    • 这对我有用,但我发现它有点难以理解。请为声明的模块 (.d.ts) 和样式表 (.scss) 提供示例文件名。如果您提供一些示例 .scss 代码以及如何访问它,这也会很有帮助。我能够使用正则表达式,但更复杂的 .scss 文件可能更难像这样定位。
    【解决方案3】:

    我有一个比较简单的方法给你:

    node-sass 步骤与ng build 步骤分开,并在您的角度应用程序中使用生成的.css 文件而不是sass 文件。

    这有两个好处:

    • 无需大量调整和编辑任何节点模块
    • 完全控制 sass 的编译方式

    对于实施,我将按照以下方式进行:

    1. ./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 中忽略它们,这样它们就不会被编译两次)。
    2. 运行一次命令npm run build-sass,以便在项目中生成.css文件。
    3. 根据需要将角度组件中的引用从.sass 更改为.css
    4. (可选)在你的 package.json 中添加一个方便的命令npm run build-sass && ng build 作为compile,你可以在你想要构建整个项目时运行它。

    虽然这种方法相对简单,但也有一些缺点

    • 对于您要使用 css 的任何组件,ng serve 的热重载功能将要求您运行 npm run build-sass 以实时查看您对样式所做的任何更改
    • 您的项目看起来会有点混乱,因为在生成.css/src 文件夹中存在相同组件的.scss.css 文件。您需要确保(例如通过添加后缀或注释)没有人意外编辑生成的 .css 并且这些更改会被覆盖。

    其他方法几乎总是涉及大量编辑现有的 webpack 编译器或编写自己的 webpack 编译器。

    【讨论】:

      【解决方案4】:

      在角度 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
          },
          ...
      ]
      }
      

      断点.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;
      //    }
      

      断点.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)
        ]
      })
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-08
        • 2014-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多