Extract specific CSS files to a file with Webpack - javascript

What I'm trying to achieve is a Webpack configuration where CSS is handled by the final JS export, but, some specific files are exported to an external file (to optimize critical CSS loading).
So, the idea is: if the file name start with _critical-, put it in a file.
So, here is my webpack.config.js for the moment:
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: './src/entry.js',
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
module: {
rules: [
{
loader: 'babel-loader',
test: /\.js$/,
exclude: /node_modules/
},
{
use: [
'style-loader',
'css-loader',
'sass-loader'
],
test: /\.s?css$/,
},
{
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
'sass-loader'
]
}),
test: /\A_critical-.*\.s?css$/,
},
{
test: /\.(png|jp(e*)g|svg)$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[hash]-[name].[ext]'
}
}]
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
],
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: path.join(__dirname, 'public'),
historyApiFallback: true
}
};
And, at some point, I have import './components/base/_critical-color.scss'; in my code.
When I run Webpack, no error. But no styles.css either.
What am I missing?

Related

CSS and other assets from the public folder not getting included in the build

In my public folder I have index.html, the css file and the fonts.
In my source folder I have the index.js file.
This is how the folder structure looks
I have setup the webpack.config.js file like this
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: path.join(__dirname, 'src', 'index.js'),
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '',
filename: 'bundle.js',
},
mode: 'development',
module: {
rules: [
{
test: /\.?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: ['#babel/transform-runtime'],
},
},
},
{
test: /\.css$/i,
exclude: /node_modules/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jp(e*)g|svg|gif)$/,
exclude: /node_modules/,
use: 'file-loader',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
exclude: /node_modules/,
use: 'url-loader',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'public', 'index.html'),
publicPath: './',
}),
],
};
Everything is working fine in dev, but when I create the build the files inside the public folder except the index.html are not included.
The dist folder after the build
You can use the copyWebpackPlugin to move the files from /public to the new build destination (/dist).
Example:
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: "./public/*", to: "./" },
],
}),
],
};
However, how are you using this CSS and Font files? Webpack should also help to pack your CSS correctly along with the rest of your code. I recommend you to follow the oficial documentation: Webpack.

Issue with integrating cortex-js/compute machine in react application

I am trying to use compute machine provided by the cortexjs. https://cortexjs.io/compute-engine
I saved this dependency using
npm i #cortex-js/compute-engine
After I ran npm start, I am getting this error:
ERROR in ./node_modules/#cortex-js/compute-engine/dist/compute-engine.min.js 2:1360
Module parse failed: Unexpected token (2:1360)
You may need an appropriate loader to handle this file type.
Following is my webpack file:
var webpack = require('webpack');
const HtmlWebPackPlugin = require("html-webpack-plugin");
var path = require('path');
module.exports = {
// output: {
// path: path.resolve(__dirname, 'dist'),
// filename: 'main.js',
// publicPath: '/'
// },
mode : 'production',
devServer: {
historyApiFallback: true,
},
devtool: "source-map",
module: {
rules: [
{
test: /\.(png|jpg|woff|woff2|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader"
}
]
},
{
test: /\.css$/,
loader: 'style-loader'
},
{
test: /\.css$/,
loader: 'css-loader',
options: {
import: true,
},
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
})
]
};
Please can someone suggest which loader should I add to webpack.config file to make this work.

Webpack doesn't emit css sourcemap (with sourcemap: true)

I can't make my webpack to emit css sourcemap. I've put sourcemap: true everywhere where possible, and no effect, and all the solutions online suggest either this or some other plugin configuration, but I don't have any other plugin, it's super simple webpack.config.js
This is my webpack.config.js:
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
var path = require("path");
module.exports = {
entry: "./main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
publicPath: "/",
sourceMapFilename: '[file].map'
},
devtool: 'source-map',
module: {
rules: [{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["es2015"],
sourceMap: true
}
}
},
{
test: /\.scss$/,
use: [{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '/',
sourceMap: true,
hmr: process.env.NODE_ENV === 'development',
},
},
{
loader: "css-loader",
options: {
sourceMap: true
}
},
{
loader: "sass-loader",
options: {
sourceMap: true
},
}
]
},
{
test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/,
use: [{
loader: 'url-loader',
options: {
name: 'images/[hash]-[name].[ext]'
}
}]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
ignoreOrder: false, // Enable to remove warnings about conflicting order
sourceMap: true
}),
],
};
I need this source map in dev mode, but only two files get emited main.css and bundle.js.
For those who also struggle with this, the below webpack.config.js is a proper configuration for having style's sourcemap in dev mode. Bundle.js needs to be included when in dev mode, and custom.min.css needs to be added to the HTML document in production mode.
Edit: Unfortunately this can be also wrong. Right now without any change to webpack or node, the sourcemap is not generating :/ sometimes it works, and sometimes it doesn't. There is some bug in webpack, or in some plugins, either way it's a serious bug, but it's webpack so I am not surprised...
Edit 2: Now I see that the problem is only in Firefox, Chrome and Opera have the correct map.
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
var path = require("path");
module.exports = {
entry: "./main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
publicPath: "/"
},
module: {
rules: [{
test: /\.js$/,
use: {
loader: "babel-loader",
options: { presets: ["es2015"] }
}
},
{
test: /\.scss$/,
use: [
{
loader: "style-loader" // creates style nodes from JS strings
},
{
loader: "css-loader" ,
options: {
sourceMap: true
}// translates CSS into CommonJS
},
{
loader: "sass-loader",
options: {
sourceMap: true
} // compiles Sass to CSS
}
]
},
{ test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/,
use: [{
loader: 'url-loader',
options: {
name: 'images/[hash]-[name].[ext]'
}
}] }
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '../css/custom.min.css'
})
]
};

Mini-css-extract-plugin doesn't bundle my css into one single file with sass

When i try to add the sass-loader and run webpack there is multiple chunck .css files in the dist folder instead of just the bundled one named "style.css".
My dist output folder looks like:
0.e749007119be51de03e4.js 1.e749007119be51de03e4.js bundle.e749007119be51de03e4.js
0.style.css 1.style.css
I guess it's because of the Mini-css-extract-plugin but i can't figure out how to fix it.
Here is my webpack file:
const webpack = require('webpack');
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ROOT = resolve(__dirname);
const SRC = resolve(ROOT, 'src');
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
entry: {
bundle: [
'react-hot-loader/patch',
'webpack-hot-middleware/client?reload=true',
resolve(SRC, 'client', 'index.js'),
]
},
output: {
path: resolve(ROOT, 'dist', 'client'),
filename: '[name].[hash].js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
include: resolve(__dirname, 'node_modules', 'react-toolbox'),
use: [
MiniCssExtractPlugin.loader,
// 'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
// 'postcss-loader'
]
},
{
test: /\.scss$/,
use: ['style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
},
{
test: /\.css$/,
exclude: resolve(__dirname, 'node_modules', 'react-toolbox'),
use: ['style-loader', 'css-loader']
},
{
test: /\.(jpe?g|svg|png|gif)$/,
use: ['file-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader']
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new MiniCssExtractPlugin({
filename: 'style.css',
}),
]
};
Any idea ?
There is two problems coming with this way. If i wanna use a plugin like html-webpack-plugin the index.html file is not filled with the anymore. Secondly the normal behavior of MiniCssExtractPlugin shouldn't be to create a file style.css like i precised in the constructor ?
No, since you have async chunks, it is going to create a style.css for each style that is removed from those async chunks.
I assure you that if you are using html-webpack-plugin it is going to work. It is just not added there because those css had not came from one of the entry points. THat is why it is not inserted directly into the html. I have a similar project and it works perfectly.
If those are not emmited from the entry point, there are going to be loaded dynamically by webpack once those chunks are requested.
Big files harms users. Code splitting is always the answer for everything!!
Check out this piece of code from the documentation
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
}
]
}
if you see carefully you'll see that it's using style-loader in dev mode and MiniCssExtractPlugin.loader for production. So in production it will generate another file for css.
What you need to do is this:
In your package.json file in the script section you need to pass a env variable devMode like this
"scripts": {
"webpack": "webpack",
"start": "npm run webpack -- --env.mode=development"
}
Then in your webpack.config.js file you need to do this
module.exports = (env) => {
const devMode = env.mode === 'development'
return {
mode: env.mode, // will be development
devtool: ...,
entry: { ... },
output: { ... },
module: {
rules: [
{
test: /\.scss$/,
use: [devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
}
]
}
}
}
That should be ok, hope it helps.

Webpack doesn't generate app.bundle.css

I have the following webpack file, however, when I run npm run dev the name.bundle.css file doesn't get generated: (no errors either)
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
context: path.resolve(__dirname, './resources/'),
entry: {
app: './index.jsx'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './public/assets/'),
publicPath: '/assets/'
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: [{
loader: 'css-loader'
}],
}),
},
{
test: /\.jsx|js$/,
exclude: [/node-modules/],
use: [
{
loader: "babel-loader",
options: { presets: ['react', 'es2015', 'stage-1'] }
}
]
},
{
test: /\.(sass|scss)$/,
use: ["style-loader", "css-loader", "sass-loader"]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: ['file-loader?name=[name].[ext]']
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file-loader?name=public/fonts/[name].[ext]'
}
]
},
resolve: {
modules: [
path.resolve(__dirname, './resources/'),
'node_modules'
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'common'
}),
new ExtractTextPlugin({
filename: '[name].bundle.css'
})
]
}
my CSS folder is:
CSS
- app.scss
COMPONENTS
comp1.scss
comp2.scss
it works this way "import styles from './css/app.scss';" but I would expect this to generate a app.bundle.css:
new ExtractTextPlugin({
filename: '[name].bundle.css'
})
You have 2 rules for both css and sass.
I think in your case you only need one:
test: /\.(sass|scss)$/,
use: ExtractTextPlugin.extract({
use: [{
loader: "css-loader"
}, {
loader: "sass-loader"
}],
fallback: "style-loader"
})
and like you said, you should import the scss files in the js files import './css/app.scss'

Categories