Utilizing node_modules CSS imports in your webpack-powered Angular 2 application

Imagine we kick things off with this nifty starter pack: https://github.com/angularclass/angular2-webpack-starter

Once we execute npm install and npm run start, everything runs smoothly.

Now, let's say I want to incorporate an external css module, like bootstrap 4's css (just the css). (I am aware of bootstrap-loader, but for now let's focus on a more general solution, using bootstrap 4 as an example).

To get bootstrap via npm:

npm install<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0e6c61617a7d7a7c6f7e4e3a203e203e236f627e666f203a">[email protected]</a> --save

Initially, I thought adding

import 'bootstrap/dist/css/bootstrap.css';
to vendor.browser.ts would suffice.

However, it turned out not to be enough.

What steps should I take for a proper solution?

Here are some solutions I'm NOT interested in:

  1. "Copy the external css module to the assets folder and use it from there"
    • I'm seeking a solution that integrates seamlessly with the npm package.
  2. "Utilize bootstrap-loader for webpack"
    • As mentioned before, I am after a generic solution, where bootstrap is just being used as an example.
  3. "Switch to a different stack"
    • I am specifically looking for a solution within the exact starter pack referenced above.

Answer №1

To include Bootstrap in your project, use

@import '~bootstrap/dist/css/bootstrap.css';
in the styles.css file. Keep in mind the use of the ~.

Note: The '~' serves as an alias specified in the webpack config that points to the assets folder.

For instance, here is an example of configuring webpack with the '~' alias in the webpack configuration file (usually named webpack.config.js):

// Add this code under the "resolve" property in webpack.config.js
// You may need to require the asset like '~/bootsrap/...'
resolve: {
  alias: {
    '~': path.resolve('./node_modules')
  }
}

Answer №2

To incorporate external CSS into your vendors file using that technology stack, some adjustments are necessary.

Why is this necessary? The reason lies in the following line of code:

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

This line simply imports your CSS as a string, whereas ideally, you would want your vendor CSS to be within a style tag. By examining the config/webpack.commons.js file, you will encounter this specific rule:

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

Through this rule, your components gain the ability to import CSS files. Essentially, it operates as follows:

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

The absence of encapsulation in the AppComponent due to the line

encapsulation: ViewEncapsulation.None,
signifies that any CSS rules will have a global application within your app. Consequently, you can bring in Bootstrap styles within your app component:

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

If you persist in importing CSS into your vendor.ts, then the inclusion of a new loader is mandatory. Execute npm i style-loader --save-dev to enable webpack to inject CSS onto your page. Subsequently, crafting a specific rule within your webpack.common.js and modifying the existing one becomes imperative:

 { //this rule will solely cater to vendors
   test: /\.css$/,
   loaders: ['style-loader', 'css-loader'],
   include: [/node_modules/]
 },
 {
   test: /\.css$/,
   loaders: ['to-string-loader', 'css-loader'],
   exclude: [/node_modules/] //incorporate this aspect to bypass CSS originating from node_modules
 },

The initial rule exclusively pertains to situations where CSS is imported from any package residing inside node_modules. Conversely, the second rule applies to any externally sourced CSS not originating from node_modules.

Answer №3

If you're looking to import multiple CSS files using angular-cli, here's a handy method that I personally find very convenient.

Simply list the CSS files in the configuration file (make sure to order them correctly if there are overrides) and let angular-cli handle the rest. For example, if you need to include styles from node-modules, you can do so like this:

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

Your complete configuration file might resemble something like this:

.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": {}
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to extract value from subscribing?

I attempted to accomplish this task, however, I am encountering issues. Any assistance you can provide would be greatly appreciated! Thank you! export class OuterClass { let isUrlValid = (url:string) => { let validity:boolean ...

Creating a user-friendly login feature within the navigation bar of an HTML webpage

As someone who is new to CSS, I am currently working on a welcome page that includes a login section in the navbar. While I have successfully created div sections for the entire page, I am seeking assistance with coding the navbar using CSS. The current C ...

Tips for troubleshooting the 404 error on nginx servers

I've got an angular 4 Single Page Application (SPA) and I'm using Docker for production. Everything seems to be going smoothly so far. When I navigate to the /dist folder in the terminal, I use the following command to point docker to the content ...

When running the command "npm start," an error occurs stating: Plugin/Preset files are prohibited from exporting objects and can only export functions

I recently started using reactJS and was following a tutorial. However, I encountered an error when trying to run "npm start". Here is the error message: ERROR in ./main.js Module build failed (from ./node_modules/babel-loader/lib/index.js): Error: Plugin ...

Text loaded dynamically is not remaining within the div

I am experiencing an issue with dynamically loaded content where Images work fine, but Links and Text are not displaying properly. For reference, you can view the problem in this JSFiddle: http://jsfiddle.net/HRs3u/1/ I suspect that it might be related t ...

Adjust the size of divs using JQuery UI's draggable feature

Looking for a way to make two divs share 100% of their parent's width, with a dynamic resizing feature in between them? Check out my solution here: http://jsfiddle.net/aRQ7a/ However, I'm facing an issue where when I decrease the size of the pre ...

Is it possible to create a sticky element that stays fixed to the window without using JavaScript?

Using position: sticky has been a game-changer for me. It resolves many issues without the need for JavaScript. However, I've encountered a roadblock. I am trying to create a sticky element that is nested inside multiple <div> elements. Since po ...

What causes child margins to extend beyond the boundaries of div elements?

Can anyone shed some light on the advantages of CSS behavior that allows a child element's top and bottom margins to extend beyond the boundaries of its block-parent? Check out this fiddle for a straightforward example. The pink div is influenced by ...

JavaScript has encountered a syntax error

When working on an animation in javascript, I encountered a problem that I can't seem to identify. I am attempting to make the pan function work with the "mover" function, but it seems like either I am not using the properties correctly within the "tr ...

Is it considered poor form to develop an npm module that relies on an external application or program for its functionality

Is it advisable for me to release an npm module that depends on an external program not available on npm (like python), and installs it using a postinstall or preinstall hook? ...

Monitoring changes to variables in Angular 5

I have a basic class that contains a boolean variable named checked. This class is then used in an array within my component, and the HTML displays each object. <tr *ngFor="let element of filteredElements"> <td> <input type="check ...

Is it possible to use CSS alone to showcase information above labels via radio tabs?

Is there a way to display content above tab labels when clicked, possibly using CSS only? When attempting to place the content div above the label, the page breaks. Any suggestions would be greatly appreciated. Thank you in advance! DEMO LINK CSS .tabs ...

Utilization of z-index with float: left within an image gallery in CSS

Currently, I am working on an image gallery that has content generated randomly. In terms of CSS, the images are positioned using the following code: .item { width: 200px; margin: 10px; float: left; } To add some functionality, I have implemented ...

TS2339: The specified property 'defaultProps' is missing from the type '(props: any) => DetailedReactHTMLElement<{ className: string; }, HTMLElement>'

When attempting to define default props using TypeScript for stateless, functional React components, the following code is used: import React from 'react' interface Props { readonly sid?: string, } const defaultProps: any = { sid: '&a ...

How to reach the Twitter share iframe with JavaScript/HTML

There seems to be an issue with the Twitter share button not displaying at its full width on certain pages. Upon investigation, I discovered that the iframe containing it is only set to a width of 24px, when it should actually be set to the correct width. ...

Is there a way to monitor HTTP requests from an Angular application within Chrome?

Is there a way to observe HTTP requests from an Angular application using Chrome DevTools? I am looking to capture a POST request when adding an item. ...

Simulating the behavior of display blocks

HTML similar to the example below is working perfectly, however, there seems to be an issue with Sharepoint 2013's editor. When trying to edit the link text within a block that has 'display: block' or 'float', it becomes impossible ...

Button addition in Angular is malfunctioning

I have a form with add and remove fields implemented using angularjs. It works fine when running outside the div, but when placed inside a div, only the remove function is working. Can you please advise on what might be going wrong? <body> <div ...

What steps can I take to resolve the issue with the cdk module?

click here for image This persistent error keeps appearing whenever I try to resize the window. I was hoping that when I decrease the page size, the search bar would transform into an icon with a dropdown search function. Despite my attempts to modify the ...

Leveraging User Location in Angular 6 using API with OpenLayers

I am currently developing a mapping application using Angular (6) and OpenLayers (4.6.5) with the initial aim of retrieving user geolocation. To achieve this, I am utilizing a French API provided by the French Government for querying and obtaining GeoJSON ...