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.
Related
I'm trying to apply CSS modules concept agains my angular app, to order embed it into existing frontend with CSS which unfortunately overlaps. My project uses scss, I want webpack "modulize" my CSS after CSS if formed from scss on last build step I think.
I want to use CSS loader of webpack to achieve this.
But I couldn't make it work.
https://www.npmjs.com/package/#angular-builders/custom-webpack
to order customize my webpack config.
I've tried to apply the next configuration
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
modules: true,
},
},
],
},
};
and got this error
ERROR in Module build failed (from ./node_modules/postcss-loader/src/index.js):
SyntaxError
(1:1) Unknown word
> 1 | exports = module.exports = require("../../../../css-loader/dist/runtime/api.js")(false);
I've tried to find and add css loader into existing
module.exports = (config, options) => {
const rules = config.module.rules || [];
rules.forEach(rule => {
if (String(rule.test) === String(/\.css$/)) {
rule.use.push({ loader: 'css-loader', options: { modules: true }})
}
});
return config;
};
Getting the same error. How to make it work?
Update 1:
I found that angular uses postcss which also provides this functionality as a plugin, postcss-modules. Also still can't make it work.
I was able to implement CSS Modules in Angular with the help of #angular-builders/custom-webpack as you suggested.
However, my solution use postcss-modules and posthtml-css-modules instead of the css-loader to hash the styles.
postcss-modules hash all the styles, then posthtml-css-modules replaces the class names on the html files by the hashed class names.
I documented my solution here:
Live Demo: https://angular-css-modules.herokuapp.com/
Github Repo: https://github.com/gquinteros93/angular-css-modules
Article with the step by step: https://indepth.dev/angular-css-modules/
I hope it will be useful for you.
I am trying to import css to my specific component of react app.
webpack config:
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({
use: 'css-loader',
}),
}
but css is not applied.
I also included the main css inside index.html. Is it the reason why I cannot apply another css file?
<link rel="stylesheet" href="../style/style.css">
Can you suggest me what's missing?
It depends on the webpack version you're using. For example, if you're using Webpack 4, then your development config would be:
{
test: /\.s?css$/, // test for scss or css files
use: [
'style-loader', // try to use style-loader or...
{
loader: 'css-loader', // try to use css-loader
options: {
sourceMap: true, // allow source maps (allows css debugging)
modules: true, // allow css module imports
camelCase: true, // allow camel case imports
localIdentName: '[local]___[hash:base64:5]', // set imported classNames with a original className and a hashed string in the DOM, for example: "exampleClassName__2fMQK"
},
},
],
}
example.css (must use camel case instead of snake case)
.exampleClassName {
text-align: center;
}
example.js
import React from 'react';
import { exampleClassName } from './example.css';
export default () => (
<h1 className={exampleClassName}>I am centered!</h1>
)
For production, you'll want to use OptimizeCSSAssetsPlugin and MiniCssExtractPlugin :
minimizer: [
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
map: {
inline: false,
annotation: true
}
}
}),
],
{
plugins: [
new MiniCssExtractPlugin({
filename: `css/[name].[contenthash:8].css`,
chunkFilename: `[id].[contenthash:8].css`,
}),
]
}
When you run webpack to build your application for production, it'll compile the css and (when the webpack config is set up properly) will generate an index.html that automatically adds a link to the compiled stylesheet.
Webpack is a steep learning curve and there's a lot of missing options from the above examples, so if you're just trying to get it up and running, then I have a Webpack-React-Boilerplate that has (s)css modules imports and a lot more already configured for you. I've included notes within the webpack config files to help assist as to what each option is doing.
Otherwise, if you're trying to learn older versions of webpack, then you can eject the create-react-app and reverse engineer/look at their extensive webpack notes.
Introduction
I have already setup bundling for my Javascript files with webpack in my project. Now I am in the process of adding CSS files to the webpack configuration. So far, I have been including the CSS files manually in the HTML header by adding <link> elements for every CSS file I depend on (e.g. bootstrap, my own css, etc.). Obviously this is not very elegant and using webpack would be much better, so I would like to replace the link elements and bundle them via webpack.
This should be easy, everything is pretty much documented in the webpack documentation. After reading the documentation and experimenting a bit with webpack I have arrived at the configuration below which already works.
Problem
The problem with my current setup is that I would like to have proper source map support and that does not seem to work. By proper, I mean that I expect that when I run a development build with webpack and I inspect some element in Chrome DevTools, that I will see from which file and which line in the file a certain CSS class originated and that I can click on the CSS rules and the browser jumps to that file.
I do not want to have inline styles in the head element, because then the browser will show something like .foobar { <style>..</style>, rather then .foobar { app.css:154.
With my current setup I have all CSS files combined (but not minified) into one app.css file. This means that if I inspect a bootstrap class such as .btn then it appears as .btn { app.css:3003. However, what I want to achieve is that the browser shows it as .btn { bootstrap.css:3003.
So now I am trying to understand how webpack and the different plugins such as css-loader and min-css-extract-plugin apply CSS source maps, and how I can configure them to achieve a proper debugging experience.
I am not sure how relevant this is, but when I navigate in DevTools under Sources to webpack://./bootstrap/dist/css/bootstrap.css I see that it only contains a single line:
// extracted by mini-css-extract-plugin.
Webpack Setup
index.js:
window.jQuery = require('jquery/dist/jquery');
require('bootstrap/dist/css/bootstrap.css');
require('bootstrap/dist/js/bootstrap');
/* other dependencies */
webpack.config.js:
const devMode = process.env.NODE_ENV !== 'production';
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
rules: [
{ /* Javascript rules excluded */ },
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
plugins: [
new UglifyJSPlugin (),
new HtmlWebpackPlugin({
template: 'app/index.tpl.html'
}),
new MiniCssExtractPlugin({ filename: devMode ?
'[name].css' :
'[name].[hash].css'
})
],
Conclusion
It seems I just passed the rubber duck test. While I was writing this I arrived at a solution. I will still publish the question, maybe it can help others.
The problem was that I was also using the mini-css-extract-plugin for development and not just for production. I thought that I needed to do that, because when at first I was using the style-loaded I would get styles included in the header and the browser would show me all styles as .foobar { <style>..</style>.
However, the actual problem seemed to be, that I was not using devtools. So the solution was to add devtool: devMode ? 'cheap-module-eval-source-map' : 'source-map', to the webpack configuration to conditionally use the style-loader plugin during development builds and mini-css-extract-plugin during production builds.
webpack.config.js
{
test: /\.css$/,
use: [
{
- loader: MiniCssExtractPlugin.loader,
+ loader: devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
}
]
},
/* ... */
+ devtool: devMode ? 'cheap-module-eval-source-map' : 'source-map',
We are developing a cloud application in angular 5 that will be deployed in a single instance but will be addressed to several customer.
The question concerns the management of themes, each customer wants to have his own theme (mainly colors).
The architecture (simplified) of the application looks like this:
--src
--app
app.component.html
app.component.scss
app.component.ts
-- component1
comp1.component.html
comp1.component.scss
comp1.component.ts
...
--scss
-- current
style.scss
_variables.scsc
-- customer1
style.scss
_variables.scss
-- customer2
style.scss
_variables.scss
...
Currently we are deploying by client, so there is no problem, we copy / paste the style in the current before the build.
Each component.scss imports _variables.scss to exploit the variables.
We would like that when a user logs on to the app, we detect the customer and choose the right style, but that the css is generated at compile time.
Is there a way to define global variables that can be modified in runtime and that impacts sub-components?
The solutions I tested:
Set in angular-cli a scss per customer, build and execute script js to modify the html link to css "href = 'assets / {customer} .bundle.css'". It works for global styles, but variables in subcomponents are not updated.
Use pure css to declare scope variables: root {--color-primary: gray; } and exploit them in the sub-components .test {color: var (- color-primary)}.
Make a JS script that will update all the global variables according to the client.
It works, but no equivalent in SCSS? strange
I do not know if I gave enough detail, thanks for the help.
As there is no proper way to do this; And solution used by Angular theming was not satisfactory to us; we've decided to use custom webpack builder that will compile our style based on the entries we provide. Please note, that we are not using SCSS in angular components explicitly.
"use strict";
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const AutoPrefixer = require("autoprefixer");
module.exports = {
entry: {
"modern_style.application": "./src/styles/modern_style.scss",
"default.application": "./src/styles/default.scss"
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].bundle.css"
})
],
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: [AutoPrefixer()],
sourceMap: true
}
},
{
loader: "resolve-url-loader"
},
{
loader: "sass-loader",
options: {
precision: 8,
includePaths: [],
sourceMap: true
}
}
]
}
]
}
};
These entry files will have their variables set & customizations applied in each respective entry file, which looks like this:
// Entry file: modern_style.scss
$someVariableToBeUsedOrOverwritten: red;
#import "common/allModulesAreImportedHere"
.customRule{
//...
}
This generated style, e.g default.bundle.css is then loaded via <link rel="stylesheet" type="text/css" [href]="linkToTheme">
There is no way to pass any variables from ts to scss.
All you need is theming.
So for each customer you need a global body class whith its own set of variables / classes.
Check out angular material theming docs for example https://material.angular.io/guide/theming#defining-a-custom-theme
Mixins will solve your issue.
In the specific customer scss files, you would be holding the specific definition.
In the component.scss, you would be using the mixin, which is specific to the customer and it will resolve your issue on both compile and run time.
I am having problem removing unused CSS in webpack 4. It seems that most of the CSS purification plugins are dependent on extract text plugin which is not updated for version 4.
Here's my commands:
node_modules/.bin/webpack --mode=development --env.operation=separateCSS
OR
node_modules/.bin/webpack --mode=development --env.operation=bundleCSS
Here's part of my webpack.config.js:
rules: [
// Loader for SASS files
{
test: /\.s[ac]ss$/,
use: [
// Use IIFE to choose how to emit the CSS: 1. Extract as separate file 2: Bundle with the JS file
(() => {
return env.operation == "separateCSS" ? MiniCssExtractPlugin.loader : 'style-loader';
})(),
{
loader: 'css-loader',
options: {
importLoaders: 1,
url: true
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
// Write future-proof CSS and forget old preprocessor specific syntax.
// Use the latest CSS syntax today with cssnext.
// It transforms CSS specs into more compatible CSS so you don’t need to wait for browser support.
// It parses CSS and add vendor prefixes to CSS rules using values from Can I Use.
// https://github.com/MoOx/postcss-cssnext
require('postcss-cssnext')()
]
}
},
'sass-loader'
]
}
],
plugins: [
new MiniCssExtractPlugin({
filename: "../css/[name].css"
})
]
Does anybody know how can I modify my config file so webpack can remove unused CSS?
Have you considered using something called uncss. There's a webpack plugin for it. It will look through all your CSS and compare it to your HTML, and remove anything that you're not using.
Take a look: WebPack UnCSS