在 Angular 2/Angular-CLI 中将 CSS 排除在 JS 之外

Posted

技术标签:

【中文标题】在 Angular 2/Angular-CLI 中将 CSS 排除在 JS 之外【英文标题】:Keeping CSS out of JS in Angular 2/Angular-CLI 【发布时间】:2017-04-26 16:11:57 【问题描述】:

默认情况下,Angular 2 将 CSS 编译成 javascript,尤其是在 Angular-CLI 中使用 WebPack 时。出于几个原因,我宁愿这不会发生。

第一个原因是,当我进行开发时,我发现能够在开发人员工具中准确查看特定样式规则来自哪个样式表以及它所在的行号确实很有帮助。第二个原因是,我认为将 CSS 编译到代码中有点忽略了良好 CSS 的要点,即您可以应用不同的样式表,并且使用相同的标记具有完全不同的外观。

我可以在某处设置一个标志以将 CSS 保留在 .css 文件中,它属于 IMO 吗?

【问题讨论】:

相关:***.com/q/40761076/854556 有人,有人吗? 有趣的问题。我刚开始使用 Angular 2,但你不能使用 styleUrls 吗? 我还没有看到一种方法可以说“嘿,不要将你找到的 CSS 编译成 JavaScript”。如果你找到了,请分享。 所以使用 styleUrls 不会从提供的 css 文件中加载,而是以某种方式将其“编译”成 JS? 【参考方案1】:

转到您的基本 html 文件(根模块、主应用程序被注入的地方)并在您的标题部分链接 CSS 样式表。

Webpack 不会将其包含在注入页面的编译/组合 css 文件中。 css 文件仍会在运行时包含在浏览器中。

<html>

<head>
  <base href="/">
  <meta charset="utf-8">
  <title>dummy</title>
  <meta name="viewport" content="width=device-width">

//was not injected/modified by webpack
  <link rel="apple-touch-icon" sizes="57x57" href="app/images/apple-icon-57x57.png">

//webpack's injected this below from other components's imported/inline css rules
<link href="index-c2cacb5fa3dfbca6116f4e4e63d5c3c7.css" rel="stylesheet"></head>

【讨论】:

如何为单个组件提供 CSS? 规则仍然有效/有效.....但在全球范围内可用。除非您为 css 类使用重叠名称,否则这不是问题。 我想我很可能会这样做。来自“CSS Zen Garden”学派,我不明白 Angular 2 中 CSS 背后的全部哲学。 追踪组件的css样式表很容易......只需找到styleUrls指向的内容或将它们添加到样式下。只要您也知道元素属于哪个组件(检查标签名称),您就可以确定哪个 css 文件。顺便说一句,webpack 这样做,而不是 angular2。 Webpack 是可选的,可以配置为忽略 css。 这并不像让开发人员工具列出应用于给定 html 元素的所有属性并在它来自的确切样式表中列出确切的行号那样简单。我怀疑没有 WebPack 的 Angular 2 会像旧的 angular route styles 那样动态生成样式标签。我还没有看到任何相关的文档。【参考方案2】:

我也使用 angular-cli (v1.0.0-beta.22)。当我准备好进行生产时,我运行以下命令:

ng build -prod -aot

这会生成我所有的生产就绪文件(捆绑、摇树和缩小等)。特别值得注意的是,它将生成两个版本的样式表。

js中的一个:

styles.b2328beb0372c051d06d.bundle.js

另一个版本是纯 css:

styles.4cec2bc5d44c66b4929ab2bb9c4d8efa.bundle.css

我使用 gulp 对 css 文件进行了一些后期处理,并将 css 版本用于我的生产构建。我确定延迟加载是否同样适用(cli 将产生不同的块),但它在不使用延迟加载时肯定有效(我还没有启动生产-准备好项目但延迟加载)。

我还尝试了使用 JiT 编译的构建:

ng build -prod

它还生成了原始/缩小版的 css 样式表。

现在,我确定以下方法不起作用:

构建

这将生成嵌入在 js 文件 styles.bundle.js 中的所有 css。

由于您想在开发期间使用原始 css 文件,我能想到的唯一解决方法是运行 ng build -prod 以获取 css文件。手动将其复制/粘贴到您的资产文件夹中。在文件上运行“格式”以取消缩小文件。然后使用引用原始 css 文件的修改过的 index.html 文件进行正常构建,并删除 styles.bundle.js 脚本引用。不漂亮,但它可能会起作用。

【讨论】:

我不知道如何防止 angular 访问 styleUrl 并将其作为 JavaScript 吸收并使其创建样式标签? 有一个新版本的 angular-cli out。它可能会解决这个问题:github.com/angular/angular-cli/pull/3511【参考方案3】:

这就是封装组件的重点。

一个组件应该有它自己的样式封装,以便它可以与样式一起发布。

假设你想发布你的一个组件供其他人使用,它不应该有自己的样式吗?

这意味着 Angular 需要一种方法将这些 css 链接到组件,从而将它们分成块并将它们注入到 head 标签中。

不过,要解决您的问题,您有几个选择:

1- 不使用仿真封装:

组件默认有一个名为 encapsulation 的属性设置为 Emulated ,您需要将其更改为 None:

@Component(
   encapsulation:ViewEncapsulation.None
)

然后,您可以将所有 css 放入自己的 head 标记中,就像使用普通 html 页面一样。

2- 如果问题是主题化,你可以让你的组件主题化。

您可以为您的组件设置一个主题属性,然后根据该属性更改样式:

@Component(
   selector:'my-component',
   styles:[
    `
       :host
          [theme="blue"]

              change what ever you want : 

              h1
                color:blue; 
              
           

       
    `
  ]
)

然后,使用这个组件就像:

  <my-component [attr.theme]='"blue"'></my-component> // would be blue theme
  <my-component></my-component> // would be default

【讨论】:

我认为您希望组件始终看起来相同的用例比您希望能够通过换出 CSS 文件来完全换出 CSS(这就是CSS 做得很好)。我认为将边缘情况优先于现实世界的正常使用是一个非常奇怪的设计决定。将所有内容放在 head 标记中的问题在于,它不会根据屏幕上组件中指定的 styleUrl 进行更新。如果您曾经在 AngularJS 中使用过 angular-route-styles,那将更接近我的预期。 不,世界正在走向组件,您真的需要谷歌搜索组件的定义!我认为你想要 JQuery ,而不是 Angular2 我认为 Angular 2 的用处不大,如果唯一想使用它的人是开发人员互相发布他们的组件。 CSS Zen Garden 哲学非常普遍,这是有原因的。 顺便说一句,我已经在 AngularJS 中使用 SVG 完成了相当多的工作,并且我已经遇到过 Shadow DOM 如何使您想做的最真实的事情变得难以实现的问题.创建一个让实际工作几乎不可能完成的框架似乎很荒谬,但却让开发人员对他们的组件的封装程度感到男子气概。 我会接受这个答案,因为我认为它最接近真实答案。其他人很好也很有帮助,但我认为这是对“Angular 2 在 CSS 方面做出了一些糟糕的设计决策,所以这是不可能的”最明确的。【参考方案4】: 在html例子中放一个包装类- <div class="component-1-wrapper"> all yout html here inside component-1-wrapper </div> 按以下方式构建您的 sass(scss)。由于您的样式封装在 component-1-wrapper 中,因此它只适用于 component-1-wrapperclass .component-1-wrapper // all the styles for component-1 here .class-hello // styles 您可以使用 sass 编译您的 css,并将所有 css(由模块分隔)放在单独的文件夹中。文件名以 _ 开头,sass 可以导入它们:

您可以在 app.ts 文件 @component( styleUrls:['styles/styles-main.scss']) 中引用您的样式-main.scss 样式表将以这种方式构造,并且单个组件的类样式将应用于特定组件,因为 html 中有一个包装器类

希望对你有帮助!!!!!!

【讨论】:

【参考方案5】:

使用 angular-cli 1.6.5 你可以这样做:

ng serve --extract-css

您仍将拥有样式封装功能,但 devtools 现在将指向组件 css 源文件。

【讨论】:

这可能是一条评论。

以上是关于在 Angular 2/Angular-CLI 中将 CSS 排除在 JS 之外的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 @angular/upgrade 在 Angular 1 应用程序中使用 Angular 2 组件

在 Angular 中添加 @uirouter/angular-hybrid 时出错

如何在 Angular 6 中使用 angular-timelinejs3?

下面的代码在 Angular 8 中运行。但我需要在 Angular 6 中执行它。我该如何实现呢?

如何在 Angular 5 的 Angular 材质 Snackbar 中添加图标

在 Storybook 中使用 @angular-redux/store 测试 Angular