How to get webpack to inline css into the generated html file - sass

I'm trying to get webpack to inline some scss into the generated html file to use as my app-shell css.
The idea is to get webpack bundle any scss file ending in '-file.scss' into a css file and to inline any scss in files ending '-shell.scss'.
This way I would get my app-shell to style before react or anything else loads.
By inline I mean to put it in STYLE tags in the generated html file.
The css part of my webpack is:
{
test: /\.css$/,
include: [paths.appSrc, paths.appNodeModules],
// Disable autoprefixer in css-loader itself:
// https://github.com/webpack/css-loader/issues/281
// We already have it thanks to postcss.
loader: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss')
},
{
test: /-shell\.scss$/,
include: paths.appSrc,
loaders: ['style', 'css', 'sass'],
},
{
test: /-file\.scss$/,
include: paths.appSrc,
loader: ExtractTextPlugin.extract('style', 'css!sass'),
},
I had thought that removing the ExtractTextPugin loader from "test: /-shell.scss$/" would do it but it doesn't put those styles into STYLE tags in the generated html build file.
I've adapted the Create React App setup from https://github.com/facebookincubator/create-react-app

Related

webpack 2 + extract-text-webpack-plugin: parsing errors

I'm trying to make a webpack config for my project with some scss. Some of it comes from the root project and some scss I want to load from dependencies e.g. from node_modules. I'm running into a strange error where if I don't include the node_modules in the module, it get's built including some scss that I have in the root project. But if I add include: path.resolve(__dirname, 'node_modules') or any other folder (eve one that doesn't exist) it fails but on file that is in root project and not in node_modules, the same files that it was extracting before with no errors.
Here is the webpack config:
const extractCSS = new ExtractTextPlugin({ filename: 'style.css', disable: false, allChunks: true });
module: {
rules: [
{
test: /\.scss$/,
include: path.resolve(__dirname, 'node_modules'),
use:extractCSS.extract({
fallbackLoader: 'style-loader',
loader: ['css-loader', 'sass-loader'],
})
},
]
}
So if I comment out the line with include it works but doesn't include node_modules and if I leave the line uncommented I get the error:
Unexpected character '#' (1:0) You may need an appropriate loader to handle this file type. in all of the scss files that are in the root project.
What am I doing wrong?

How to combine `css-modules` with normal `sass`, preferably in `webpack`

TLDR: How to combine css-modules with normal sass, preferably in webpack.
The Setup:
I am working on the styling build process for an e-commerce website. The site's styles are currently done in sass along with the js through a gulp browserify build process.
I have recently added a single page app that is built using react with webpack and babel. Inside of that application I am taking advantage of css-modules provided by webpack to scope the class names to each react component.
The problem:
I would like to incorporate the styles from the webpack css-modules build in with the main styling bundle for the site. To do this, I was considering building a webpack configuration to build the styles for the whole site. The problem I have is how to get the styles which are currently built by the single page webpack configuration and inject just the style chunk into a global webpack configuration that handles styles for the whole site. I should mention that I would like to keep the two configurations as separate as possible
The Questions:
Is there a proper way of having decoupled webpack builds where one is still able to use chunks from the other?
If so, how do I do it so that the css-module setup stays in the single page configuration, and the extract-text-webpack part along with a boring sass build goes into a global configuarion?
If not, how should I go about having one section of sass go through the css-modules workflow, and still combine it with the bundle from the rest of the site.
Thanks in advance.
EDIT
based on #Alexandr Subbotin's answer, I have updated my webpack to look something like the code below. I did have to change names and paths because of the code belongs to my employer, so there may be slight errors.
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const JSDIR = './build/js/';
const STYLES = './build/css/bundle.css';
module.exports = {
entry : {
'styles' : './src/styles.scss',
'app' : './src/index.js',
// a javascript file that includes the root of the single page app.
'single-page' : './src/single-page/styles-entry.js',
},
output : {
path : JSDIR,
filename : '[name].js', // normally compiles my
publicPath: 'http://localhost:8080/',
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader : 'babel-loader',
query : {
presets: [
'react','es2015','stage-0',
]
},
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract('style?sourceMap', 'css?-url&sourceMap!sass?sourceMap'),
exclude : /\/single-page\//,
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract(
'style?sourceMap',
'css?-url&modules&importLoaders=1&localIdentName=SinglePage__[name]__[local]!sass?sourceMap'
),
include : /\/single-page\//,
}
]
},
plugins : [
new ExtractTextPlugin(STYLES, {
allChunks : true,
}),
],
resolve : {
alias: {
"eventEmitter/EventEmitter": "wolfy87-eventemitter",
},
extensions: ['', '.js','.jsx'],
},
}
If I understood your question you want to apply css-modules only to one part of your application and leave simple sass building process in other parts.
To do this you can use exclude and include options in loaders. I.e. if you have your single page application inside single-page directory your webpack config can be:
module: {
entry: {
// it is your global sass styles
application_css: './css/application.scss',
// it is main file of your SPA bundle. Somewhere inside you will use require('./styles.scss') that should be processed by css-modules
spa_index: './single-page/index.js'
},
loaders: [
...,
{
// This loader will build all your sass that are not in `single-page` directory
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', 'css!sass'),
exclude: /\/single-page\//
},
{
// This loader will handle all your css module in `single-page` directory
test: /\.scss$/,
loader: 'style!css?modules!sass',
include: /\/single-page\//
},
],
...
}
So, in this case all css from single-page/ will use css modules, and the rest won't.
EDIT:
If you take a look in API section of ExtractTextPlugin documentation you find
The ExtractTextPlugin generates an output file per entry, so you must use [name], [id] or [contenthash] when using multiple entries.
In your example you have have two chunks with css (styles and single-page), but only one output ./build/css/bundle.css. If you change your output to ./build/css/[name].css your will have two css files: styles.css with your global css and single-page.css with SPA styles.

Webpack 2 - compile scss to css and miniffy, together with sourcemaps

I'm completely new to webpack (been using gulp since... forever).
However, I've just decided to use webpack. Decided to go with webpack 2 (2.1.0-beta.20 currently).
Been looking all over, still couldn't do a simple task as "give webpack my bootstrap.scss file (which imports all other bootstrap partial scss files needed) and have returned bootstrap.custom.min.css and bootstrap.custom.min.css.map".
I have my own bootstrap.scss file which only imports what I need from bootstrap (not using all of it), but after a custom custom-variables.scss file imported at the top, to overwrite some default bootstrap variables - like colors, grid columns etc. Anyway, I'm sure this is not relevant... The issue is compiling scss to css with custom output file name and sourcemap.
Not that it would make any difference, but to start with, here's my custom bootstrap.scss:
#import "custom-variables"; // to overwrite default bootstrap variables
/**
* Twitter Bootstrap
* This is actually copy/paste from the original bootstrap file, just changed paths
*/
// Core variables and mixins
#import "../../../../node_modules/bootstrap/scss/variables";
#import "../../../../node_modules/bootstrap/scss/mixins";
// and so on... only what I need. I don't need tables, forms and a few other.
In addition to this, I also have my own style.scss for which I need to do the same (to have returned style.min.css and style.min.css.map).
As for my webpack.config.js file, this is all I have:
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const sassLoaders = [
'css-loader',
'postcss-loader',
'sass-loader?indentedSyntax=sass&includePaths[]=' + path.resolve(__dirname, './dev')
];
const config = {
entry: {
'bootstrap.custom.min': ['./wp-bootstrap'], // this file only contains 1 line: require('./dev/css/overwrite/bootstrap/bootstrap.scss');
'style.min': ['./wp-style'], // this file also contains 1 line: require('./dev/css/style.scss');
},
module: {
loaders: [
{
test: /\.scss$/,
loader: 'file',
// or, other examples I've found said to use:
// loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loaders: 'css!sass' }),
// but if I try like that, I get: "Cannot read property 'query' of undefined"
query: {
name: '[name].css'
}
}
]
},
plugins: [
new ExtractTextPlugin('[name].css')
],
postcss: [
autoprefixer({
browsers: ['last 2 versions']
})
],
resolve: {
modules: [
path.resolve('./'),
'node_modules'
]
}
};
module.exports = config;
These are all the related packages I have installed:
"devDependencies": {
"autoprefixer": "^6.4.0",
"css-loader": "^0.23.1",
"extract-text-webpack-plugin": "^2.0.0-beta.3",
"node-sass": "^3.8.0",
"postcss-loader": "^0.9.1",
"sass-loader": "^4.0.0",
"style-loader": "^0.13.1",
"webpack": "^2.1.0-beta.20"
}
If I use a version of extract-text-webpack-plugin which is <2.x, then I get other errors, it's not compatible with webpack 2.
So, baby steps in the code above... Simply tried to at least obtain my bootstrap.scss and style.scss transformed into 2 separate css files: bootstrap.custom.min.css and style.min.css (don't know what to do about sourcemaps yet).
This is all I could come up with after searching google and trying to follow some examples. No solid tutorial out there that could make me understand how to use webpack for what I need to accomplish. I'm only guessing here, blind-folded.
But when I type webpack in the console and hit Enter, I don't get any css file, instead I get the following 3 files:
bootstrap.css - with the exact same content as the source
bootstrap.scss, like it just copies the file content over, instead of compiling scss to css;
bootstrap.custom.min.js which has a bunch of javascript code in
it;
style.min.js - which also has a bunch of javascript code in it.
I've been stuck here for days, didn't even get to all the rest I need (sourcemaps and a destination folder of my choosing for the css files and css.map files).

Webpack 2.1.0-beta.6 config file not picking up loaders for styling on windows

I'm trying to get webpack 2.1.0-beta.6's style, css, less, and file loaders to catch on Windows Server 2008, Babel 6, and Node 4.3. If webpack has this loader configuration:
loaders: [
{
test: /\.less$/,
loaders: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /.gif$/,
loader: 'file'
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015-native-modules']
}
}
The import require('../styling/my-style.less') fails with
ERROR in ../styling/my-less.less Module parse failed:
.../my-style.less
Unexpected character '#' (1:0) You may need an appropriate loader to
handle this file type. | #import "other.css";
./my-js.js 8:0-38
require('style!css!less!../styling/my-style.less') sort of works though. At least until it gets to a .gif file.
ERROR in ../styling/themes/base/images/animated-overlay.gif Module
parse failed:
..\styling\themes\base\images\animated-overlay.gif
Unexpected character ' ' (1:7) You may need an appropriate loader to
handle this file type. (Source code omitted for this binary file) #
./~/css-loader!./~/less-loader!../styling/my-style.less
10:46994-47046
My webpack config is in with my src directory and styles is a parallel directory
src
webpack.config.js
my-js.js // file doing the import from styling
styling
my-style.less
None of my loaders were getting picked up because under module.exports, I didn't have a module wrapping my loaders.
module.exports.loaders //doesn't work and require acts like there aren't loaders associated with the file type
module.exports.module.loaders //works

Webpack SASS-loader include statement breaks SASS #import statemetns

So for background originally I was excluding the node_modules directory in my Webpack config, which was working fine for my sass #import statements, but made it very difficult to include things from the node_modules directory. So I switched the SASS loader to the following
{
test: /\.scss$/,
include: [path.resolve(__dirname, "/src/client"), path.resolve(__dirname, "/node_modules/angular-material/")],
loader: 'style-loader!css-loader!autoprefixer-loader!sass-loader'
},
Please also note I tried with and without the trailing slash on client.
All my src files including the sass files are in ./src/client directory including sub-directories. The problem now is when I run Webpack all my import statements are no longer functional. and I end up with the following error whenever I try to import one of my own sass files:
ERROR in ./src/client/app/app.scss
Module parse failed: /Users/mikedklein/development/vncuxf/src/client/app/app.scss Line 1: Unexpected token ILLEGAL
You may need an appropriate loader to handle this file type.
| #import 'common/common';
| #import 'general';
|
# ./src/client/app/app.module.es6 85:0-21
If I comment out the include statement all is well, but I know this is not a good approach. For reference I have also included my resolve statement from my config:
// Resolves so require statements don't need extentions
resolve: {
extensions: ['', '.js', '.es6', '.scss', '.css', '.html', '.json'],
alias: {
angular_material_scss: __dirname + "/node_modules/angular-material/angular-material.scss"
}
}
So I think I solved this
module: {
loaders: [
{
test: /\.(es6|js)$/,
exclude: /node_module/,
loader: 'babel-loader'
},
{
test: /\.css$/,
exclude: /node_modules/,
loader: 'style-loader!css-loader!autoprefixer-loader'
},
{
test: /\.scss$/,
loader: 'style-loader!css-loader!autoprefixer-loader!sass loader'
}
]
},
// This is the key need to have include paths in the sass loader option.
sassLoader: {
includePaths: [path.resolve(__dirname, './src/app'), path.resolve(__dirname, '/node_modules/angular-material')]
}
One thing I am still curious about is whether this is the most efficient approach, when sass files are stored in multiple directories.

Resources