如何在Webpack Angular2应用程序中从node_modules导入CSS

72
假设我们从以下起始包开始: https://github.com/angularclass/angular2-webpack-starter 在运行了 "npm install" 和 "npm run start" 之后,一切都正常。
我想添加一个外部 CSS 模块,例如 Bootstrap 4 的 CSS(仅限 CSS)。(我知道 Bootstrap 有一个 bootstrap-loader,但现在我要求通用解决方案,请将 Bootstrap 4 视为可以通过 npm 获得的任何其他 CSS 模块。)
我通过 npm 安装了 Bootstrap:npm install bootstrap@4.0.0-alpha.4 --save 最初我认为只需将 "import 'bootstrap/dist/css/bootstrap.css';" 添加到 vendor.browser.ts 文件中就可以了。
但是这样不够。
我该怎么做才能有一个适当的解决方案呢?
我不需要的解决方案:
1. "将外部 CSS 模块复制到资源文件夹中,并从那里使用"
- 我正在寻找与 npm 包一起使用的解决方案。
2. "为 Webpack 使用 bootstrap-loader"
- 如上所述,我正在寻找通用解决方案,Bootstrap 只是一个例子。
3. "使用另一个堆栈"
- 我正在寻找精确的起始包中的解决方案。

你有收到任何错误吗? - Jorawar Singh
这是我参与过的最好的 SO 主题。非常棒的问题以及两个同样出色的答案。感谢大家。 - adamdport
3个回答

108

通过在 styles.css 文件中使用 @import '~bootstrap/dist/css/bootstrap.css'; 是可行的。(请注意 ~

编辑:它是如何工作的 - '~' 是 webpack 配置中指向 assets 文件夹的别名...就这么简单。

编辑2:如何使用 '~' 别名配置 webpack 的示例... 将以下代码放入 webpack 配置文件中(通常是 webpack.config.js)...

// look for the "resolve" property and add the following...
// you might need to require the asset like '~/bootsrap/...'
resolve: {
  alias: {
    '~': path.resolve('./node_modules')
  }
}


1
这对我很有用,我真的很喜欢将我的CSS文件包含在内的想法,所以我不想使用ViewEncapsulation.none。但是这是如何工作的呢? - Grez.Kev
据我所知,这是关于编译器的一些内容,但由于我不是专家,我将把这个问题留给更懂的人来解释它的工作原理... - Anderson Ivan Witzke
1
我尝试了这个,但是出现了错误:GET http://localhost:55490/~bootstrap/css/bootstrap.min.css 404 (未找到)。 - CarCar
2
对于那些想要了解这个是如何工作的人,这里有一篇不错的阅读材料:https://blog.angularindepth.com/this-is-how-angular-cli-webpack-delivers-your-css-styles-to-the-client-d4adf15c4975 - Himanshu Arora
这在Angular 6中以前不起作用,但在Angular 7中可以工作。虽然我在更改日志中没有看到任何解释,但有人知道吗? - MartaGalve
显示剩余2条评论

82

如果不进行一些更改,就不能使用该堆栈将任何CSS导入到您的供应商文件中。

为什么?因为这行代码:

import 'bootstrap/dist/css/bootstrap.css';

它只是将你的CSS作为字符串导入,而实际上你想要的是在样式标签中放置供应商的CSS。 如果您检查config/webpack.commons.js,您会找到此规则:

 {
   test: /\.css$/,
   loaders: ['to-string-loader', 'css-loader']
 },

这个规则允许您的组件导入css文件,基本上就是这样:

@Component({
  selector: 'app',
  encapsulation: ViewEncapsulation.None,
  styleUrls: [
    './app.component.css' // this why you import css as string
  ],

在AppComponent中没有封装,因为这行代码encapsulation: ViewEncapsulation.None,的存在,这意味着任何CSS规则都将全局应用于您的应用程序。因此,您可以在应用程序组件中导入Bootstrap样式:

@Component({
  selector: 'app',
  encapsulation: ViewEncapsulation.None,
  styleUrls: [
    './app.component.css',
    '../../node_modules/bootstrap/dist/css/bootstrap.css'
  ],

但如果您坚持要将其导入到vendor.ts中,则需要安装一个新的加载器,npm i style-loader --save-dev,这将允许webpack将CSS注入到您的页面中。然后,您需要创建一个特定的规则,在您的webpack.common.js文件中更改现有的规则:

 { //this rule will only be used for any vendors
   test: /\.css$/,
   loaders: ['style-loader', 'css-loader'],
   include: [/node_modules/]
 },
 {
   test: /\.css$/,
   loaders: ['to-string-loader', 'css-loader'],
   exclude: [/node_modules/] //add this line so we ignore css coming from node_modules
 },

只有在从node_modules中导入CSS时才会应用第一条规则,而从node_modules以外导入CSS时将应用第二条规则。


1
谢谢,伙计。这是我一直在寻找的完美答案。两种解决方案都很好用。有一件事我不知道,就是可以从styleUrls中定位到node_modules。这也是首选的做法吗? - Burnee
1
没有对错之分,两种方法都是有效的,但如果将来您计划将您的vendor.css放在单独的文件中,则最后一种选项更好。 - Fabio Antunes
请注意,angular2-webpack-starter已经在其package.json中装有style-loader(这意味着在此示例中无需进行额外的npm安装即可使用它)。 - Burnee
@Burnee 是的,但它并没有被任何地方使用,所以他们可能会在将来删除它。因此,为了未来的读者着想,我会把它留在答案中。 - Fabio Antunes
如何让我的Angular应用程序将已安装库的导入@import“〜dist / 3rd_party_lib / blabla.css”视为node_modules / dist / 3rd_party_lib / blabla.css,而不是https:// localhost:4200 /〜/ dist / 3rd_party_lib / blabla.css - Alexander
这是我找到的最佳解决方案。此外,您可以在任何 scss 或 css 文件中导入您的leaflet css文件,如下所示: @import "leaflet/dist/leaflet.css"; 在编译时,Angular将直接从node_modules文件夹中导入。 - undefined

22

以下是使用angular-cli导入各种CSS文件的最方便方法。

基本上,您可以在配置文件中引用CSS文件(如果要覆盖它们,则顺序很重要),然后angular-cli会处理剩下的部分。例如,您可能希望从node-modules中包含几个样式,可以按照以下方式完成:

"styles": [
    "../node_modules/font-awesome/css/font-awesome.min.css",
    "../node_modules/primeng/resources/primeng.min.css",
    "styles.css"
  ]

一个示例完整配置可能如下所示:

.angular-cli.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "my-angular-app"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.app.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "styles": [
        "../node_modules/font-awesome/css/font-awesome.min.css",
        "../node_modules/primeng/resources/primeng.min.css",
        "styles.css"
      ],
      "scripts": [],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ],
  "e2e": {
    "protractor": {
      "config": "./protractor.conf.js"
    }
  },
  "lint": [
    {
      "project": "src/tsconfig.app.json",
      "exclude": "**/node_modules/**"
    },
    {
      "project": "src/tsconfig.spec.json",
      "exclude": "**/node_modules/**"
    },
    {
      "project": "e2e/tsconfig.e2e.json",
      "exclude": "**/node_modules/**"
    }
  ],
  "test": {
    "karma": {
      "config": "./karma.conf.js"
    }
  },
  "defaults": {
    "styleExt": "scss",
    "component": {}
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接