How to bundle Angular 2 component css? - css

In my application for angular 1 I used to bundle all of the css in library.css and application.css. While this can be done with angular 2 the same way for ordinary css, there is a new feature that allows a "component css". As far as I can see Angular just downloads the css file and then processes it to add some id's to not interfere with each other.
Now if I just bundle all of these css'es Angular just won't be able to find them. Is it possible at all to do bundling of component css? Perhaps a similar way to bundling HTML exists, where HTML is really put into .js as string?

I managed to achieve this with webpack and a special angular2-template-loader plugin. This is the config from webpack 2:
module: {
rules: [
{
test: /\.ts$/,
use: ['awesome-typescript-loader', 'angular2-template-loader']
}
Basically what it does, it replaces templateUrl and styleUrls with inline template and styles and just stores them in a string as a separate "module".
How does it work
The angular2-template-loader searches for templateUrl and styleUrls
declarations inside of the Angular 2 Component metadata and replaces
the paths with the corresponding require statement. If keepUrl=true is
added to the loader's query string, templateUrl and styleUrls will not
be replaced by template and style respectively so you can use a loader
like file-loader.
The generated require statements will be handled by the given loader
for .html and .js files.
P.S. The whole set up can be found in Anagular tutorial.

These are the combination of the loaders that does the trick if you have
templateUrls and styleUrls
loaders: [{
test: /\.ts$/,
loaders: ['awesome-typescript-loader', 'angular2-template-loader']
},
{
test: /\.html$/,
loader: 'raw-loader',
exclude: [root('src/index.html')]
},
{
test: /\.css$/,
loader: 'to-string-loader!css-loader'
}
],
and in the code
#Component({
selector: 'my-app',
templateUrl: 'sub.component.html',
styleUrls: ['app.component.css']
})
export class AppComponent {
}

Related

webpack 4: Create multiple theme css files

I need to create multiple theme CSS files using webpack version 4 and "mini CSS extract plugin" in my react project. Depends on a place where webpack will find an import of the SCSS file, it should use loader twice - with different data in sass-loader options.
I found nothing useful in the Internet according this goal. I also have already tried to use such webpack's loaders as: webpack-combine-loaders, multi-loader etc...
here is a part of webpack config
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
'css-loader',
{
loader: "sass-loader",
options: {
data: '$theme: dark;',
}
},
],
},
{ // the same except data in options
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
'css-loader',
{
loader: "sass-loader",
options: {
data: '$theme: white;',
}
},
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: 'client.white.css',
}),
new MiniCssExtractPlugin({
filename: 'client.dark.css',
}),
],
and in my scss file (button.scss) I use such condition:
$background: #06cc1a;
$color: white;
#if $theme == dark {
$background: white;
$color: black;
}
.button {
background-color: $background;
color: $color;
}
}
as a result, I want to get two CSS files client.white.css where were applied sass variables for the white theme and client.dark.css where were applied variables for the dark theme
We solved this in our project by using multiple entry points, one for each theme, e.g:
entry: {
light: './src/css/light.scss',
dark: './src/css/dark.scss'
}
With the contents of light.scss files being as follows:
$background: #001560;
#import "~base/scss/base.scss";
Webpack will output a single css file for each theme containing all the styles, both base and theme-specific, which is great when optimising for production.
Note though that you will also get a redundant JS file, which you may want to clean up post-build.
I worked on a web app which use multi theme, and we tackle the problem by saving each theme's colors to backend, so we can get the value from API depending from query, and for styling, we use styled-components for that.
I find css-in-js is really useful in this kind of problem. We actually use both styled components and LESS css for our styling. styled-components are used for coloring based on theme, and the rest is on LESS css. Perhaps you can try to use that too, or even a inline css should do the work since JS variable would work on that.
A specific example is to build a ThemeProvider component that engulf the whole application as its child, ThemeProvider will contain the declaration of class with the use of styled-components and that class can be reused throughout application scope.

Move css to an external file in an angular 4 component using webpack

This is the error I'm getting:
Error: Expected 'styles' to be an array of strings.
even though I've specified the styles in an array of strings:
styleUrls: ['./app.component.css']
Here is the relevant code, any ideas what I'm doing wrong?
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: `<h2 class="float-left">Hey</h2>`,
styleUrls: ['./app.component.css']
})
export class AppComponent { }
app.component.css
.float-left {
float: left;
}
Snippet from webpack.common.js
module: {
rules: [{
test: /\.ts$/,
loaders: ['awesome-typescript-loader', 'angular2-template-loader']
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
test: /\.css$/,
loader: 'css-loader'
}]
},
As I have not personally experienced this - I did find a closed thread (but with some recent additions, nonetheless) - that may help you with your issue.
https://github.com/webpack-contrib/style-loader/issues/123
The first suggested, and apparently working at the time, solution that sticks out to me is this one:
{ test: /\.css$/, loaders: ['to-string-loader', 'css-loader'] }
There are other suggestions and solutions listed further down; hopefully one of those will help you resolve your problem.
One thing to note - it seems it may/may not make a difference if you're using angular-cli. If you are, then make sure you're following their guidelines with using webpack, as they have a couple small differences, as opposed to using a non-angular-cli build.
You need to use style-loader after css-loader.
test: /\.css$/,
use: [{loader: 'style-loader'},{loader: 'css-loader'}]
The loaders in the "use" array are run in order from the last in the array to first in the array. First the css-loader is run to prepare the CSS, then the result is passed to the style-loader to embed the styles in the page.

Vue.js + Webpack multiple style tas output

I have several vue.js components, written in single page component format.
For each .vue file, I have less written specific for that page.
After bundling, I have several style tags, which populate the global style space. Thus, some of my classes are overlapping on different pages.
Is this the intended functionality with vue.js and webpack?
This is the default behaviour for vue-loader (which is the main plugin in the vue-webpack template).
However, if you want to you can extract all CSS into one file:
npm install extract-text-webpack-plugin --save-dev
// webpack.config.js
var ExtractTextPlugin = require("extract-text-webpack-plugin")
module.exports = {
// other options...
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue'
},
]
},
vue: {
loaders: {
css: ExtractTextPlugin.extract("css"),
// you can also include <style lang="less"> or other langauges
less: ExtractTextPlugin.extract("css!less")
}
},
plugins: [
new ExtractTextPlugin("style.css")
]
}
Check out the docs of vue-loader regarding extraction.

Adding less support to a production webpack configuration (from Facebook's create-react-app)

I have forked (or ejected) off Facebook's create-react-app project, with the requirement to add a few additional tools (e.g. testing, redux, less etc.), and the perhaps naive assumption that straying a bit off the path wouldn't be too much of a problem.
I think I have just about managed to add less using the following webpack.config.dev.js:
//......
module: {
preLoaders: [
{
test: /\.js$/,
loader: 'eslint',
include: paths.appSrc,
}
],
loaders: [
// Process JS with Babel.
{
test: /\.js$/,
include: paths.appSrc,
loader: 'babel',
query: require('./babel.dev')
},
{
test: /\.css$/,
loader: 'style!css!postcss'
},
{
test: /\.less$/,
loader: 'style!css!postcss!less'
},
{
test: /\.json$/,
loader: 'json'
},
//......
}
]
},//.....
I have left the CSS loader in there (perhaps incorrectly) so that I can bring in the react/bootstrap library. Perhaps there is a better way of doing this.
Anyway, I am confused about how to add a pre-processor into webpack.config.prod.js. Here is a snippet (with Facebook's helpful comments):
loaders: [
// Process JS with Babel.
{
test: /\.js$/,
include: paths.appSrc,
loader: 'babel',
query: require('./babel.prod')
},
// The notation here is somewhat confusing.
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader normally turns CSS into JS modules injecting <style>,
// but unlike in development configuration, we do something different.
// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
// (second argument), then grabs the result CSS and puts it into a
// separate file in our build process. This way we actually ship
// a single CSS file in production instead of JS code injecting <style>
// tags. If you use code splitting, however, any async bundles will still
// use the "style" loader inside the async code so CSS from them won't be
// in the main CSS file.
{
test: /\.css$/,
// "?-autoprefixer" disables autoprefixer in css-loader itself:
// https://github.com/webpack/css-loader/issues/281
// We already have it thanks to postcss. We only pass this flag in
// production because "css" loader only enables autoprefixer-powered
// removal of unnecessary prefixes when Uglify plugin is enabled.
// Webpack 1.x uses Uglify plugin as a signal to minify *all* the assets
// including CSS. This is confusing and will be removed in Webpack 2:
// https://github.com/webpack/webpack/issues/283
loader: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss')
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
How can I add a less pre-processor step in a stable and performant way?
For context my index.js imports look as follows:
import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/css/bootstrap-theme.css';
import { CommentsSectionContainer } from './components/CommentsSection';
import './index.less';
Install less and less-loader from npm or yarn:
npm install --save-dev less less-loader
Follow this link to install extract-text-webkit-plugin:
https://github.com/webpack/extract-text-webpack-plugin
First you need to add the loader in the loaders array, after css probably makes sense for readability. It will look like this:
{
test: /\.less$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
}
Then initialize the plugin in the plugins array:
new ExtractTextPlugin('[name].css')
Thaaaaaat should do it with another yarnpkg start

How to use SASS for components style in Angular 2?

In Angular 2 when we define a component we can specify a styleUrls property to the decorator which points to a set of stylesheets to be applied to the component:
#Component({
selector: 'the-app'
templateUrl: 'templateFile.html',
styleUrls: ['componentStyles.css', 'moreComponentStyles.css']
})
export class TheAppComponent {}
Now, what if I want to write these styles with SASS?
I know I would need to use Gulp or Grunt to transpile the SCSS stylesheets to plain CSS. But this makes me confused on how we would correctly point Angular to the correct stylesheets.
How could I organize this workflow of using SASS with Gulp/Grunt together with Angular 2? How to use SASS to write the Angular 2 components styles?
After following this wiki, I got some Error: Uncaught (in promise): Expected 'styles' to be an array of strings which I resolved using this answer.
Final solution is here:
home.component.ts:
import { Component } from '#angular/core';
#Component({
selector: 'home',
template: require('./home.component.html'),
styles: [ String(require('./home.component.scss')) ]
})
export class HomeComponent { }
webpack.conf.js: (part of it)
{
test: /\.(css|scss)$/,
loaders: [
'style',
'css',
'sass',
'postcss'
]
},
You can use .scss in Component like this-
styles: [require('normalize.css'), require('./app.scss')],
See if this helps.
I'm using it this way:
import {Component} from "#angular/core";
// for webpack
require('./footer.scss');
#Component({
selector: 'footer',
templateUrl: 'app/footer/footer.html',
styleUrls: ['app/footer/footer.scss'],
})
export class FooterComponent {}
Command line inside project folder where your existing package.json is: npm install node-sass sass-loader raw-loader --save-dev
In webpack.common.js, search for "rules:" and add this object to the end of the rules array (don't forget to add a comma to the end of the previous object):
{
test: /\.scss$/,
exclude: /node_modules/,
loaders: ['raw-loader', 'sass-loader'] // sass-loader not scss-loader
}
Then in your component:
#Component({
styleUrls: ['./filename.scss'],
})

Resources