When i Webpack my project using MiniCssExtractPlugin to separate css into files, it creates the main.css file but never write the link into my html file.
Here is my webpack.config.js :
const webpack = require("webpack");
const path = require("path");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin")
const dev = process.env.NODE_ENV ==="dev"
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
let cssloaders = [MiniCssExtractPlugin.loader, {loader: 'css-loader', options:{importLoaders: 2, modules: true } } ]
if(!dev) {
cssloaders.push( {
loader: 'postcss-loader',
options : {
plugins: (loader) => [
require('autoprefixer')( { browsers : ['last 2 versions', 'ie > 8']
}),
]
},
})
}
let config = {
mode : 'none',
entry: "./assets/js/app.js" ,
output: {
path: path.resolve(__dirname, "./dist"),
filename: "bundle.js",
publicPath: "/wp/dist/"
},
devtool : dev ? "cheap-module-eval-source-map" : "source-map",
watch : dev,
module : {
rules : [
{
test : /\.js$/,
exclude: /(node_modules|bower_components)/,
use : [
'babel-loader'
]
},
{
test : /\.css$/,
use: cssloaders
},
{
test : /\.scss$/,
use:
[
...cssloaders,
'sass-loader'
]
,
},
]
},
plugins : [
new MiniCssExtractPlugin({
filename : '[name].css',
chunkFilename: "[id].css"
})
],
optimization : {
minimize : !dev
}
}
if(!dev){
config.plugins.push(new UglifyJsPlugin({
sourceMap : true
}))
}
module.exports = config;
So the loaders are in correct order : postcss-loader (if not in dev), sass-loader (for scss test), css-loader and MiniCssExtractPlugin.
When I webpack, the main.css fil is well emitted, but the html file doesn't have the link href in the head written...so there is no css :-)
bundle.js 4.85 KiB 0 [emitted] main
main.css 67 bytes 0 [emitted] main
I think i miss something ?
Thank you in advance !
It's normal behavior because mini-css-extract-plugin only help you to extract css into seperate css file instead of include css in js file.
You need to use html-webpack-plugin to include your css into html otherwise you have to add css in your html manually
I just add the main.css file to my HTML manually, without needing to install any extra plugins. I'm ok with this because the file never changes its name.
<link rel="stylesheet" href="/public/css/main.css">
Related
I have a situation when I have multiple themes in a project and every theme has it's [theme-name].scss file and [theme-name].js file which has to be compiled into [theme-name]/dist folder. So I have multiple entries with multiple outputs.
I thought I've found the simplified solution on Webpack's page here: https://v4.webpack.js.org/guides/entry-advanced/ , however only 2 js files are built into dist folder and no css. Maybe someone could tell me why it's so? Thank you.
My exact config:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: process.env.NODE_ENV,
entry: {
home: ['./src/js/home.js', './src/scss/home.scss'],
account: ['./src/js/account.js', './src/scss/account.scss'],
},
output: {
filename: '[name].js',
},
module: {
rules: [
{
test: /\.scss$/,
use: [
// fallback to style-loader in development
process.env.NODE_ENV !== 'production' ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css'
}),
],
};
file structure
For 2 days I have been trying to compile the js and css file to a separate file because now everything is together. Does anyone have any idea how this can be solved?
I would be very grateful for your help.
There is my code webpack.config.js
const path = require('path');
const webpack = require('webpack');
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'src/dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.scss$/,
use: [
"style-loader", // creates style nodes from JS strings
{
loader: "css-loader",
options: {
url: false
}
},
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
},
]
},
plugins: [
new BrowserSyncPlugin({
// browse to http://localhost:3000/ during development,
// ./public directory is being served
host: 'localhost',
port: 3000,
files: ['./src/*.html'],
server: { baseDir: ['src'] }
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
};
I think MiniCssExtractPlugin is what you are looking for.
It takes the output of css-loader and create .css bundles. It takes care of downloading them in the browser (by pushing a section of code in webpack runtime code), and also yeah, it minifies the .css :).
Simple usage:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
};
Yes you are right. Style-loader creates javascript snippets that later in runtime creates .css rules and push them to the browser global css scope.
The following configuration is made by hand to support all technologies given in the title (webpack, typescript, phaser and angular).
It works great for angular component stylesheet. But it looks like it's impossible to include a global style sheet. Here are related configuration files:
HTML file:
<!-- src/index.html -->
<!DOCTYPE html>
<html>
<head>
<base href="/">
<meta charset="UTF-8">
<!-- it's included here! -->
<link rel="stylesheet" href="styles/main.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<app-root></app-root>
</body>
</html>
CSS file:
/*
src/styles/main.css
This file is correctly loaded in dev environment. When I build the project it disapear. :(
*/
body {
background: #253050 url('../assets/design/main_background.jpg') no-repeat center;
}
And webpack configuration:
// config/webpack.common.js
'use strict';
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
var helpers = require('./helpers');
var distDir = path.resolve(__dirname, '../dist');
// Phaser webpack config
const phaserModule = path.join(__dirname, '/../node_modules/phaser-ce/');
const phaser = path.join(phaserModule, 'build/custom/phaser-split.js');
const pixi = path.join(phaserModule, 'build/custom/pixi.js');
const p2 = path.join(phaserModule, 'build/custom/p2.js');
module.exports = {
entry: {
'polyfills': './src/polyfills.ts',
"app": "./src/main.ts"
},
// What files webpack will manage
resolve: {
extensions: ['.js', '.ts', '.tsx'],
alias: {
'phaser': phaser,
'pixi': pixi,
'p2': p2
}
},
output: {
path: distDir,
filename: '[name]_bundle.js'
},
module: {
rules: [
{ test: /assets(\/|\\)/, use: [ 'file-loader' ] },
{
test: /\.tsx?$/,
// ts-loader loads typescript files
// angular2-template-loader is needed to load component templates
loaders: ['ts-loader', 'angular2-template-loader'],
exclude: [
/.+phaser-ce\/typescript\/.+\.ts$/,
/typescript\/.+\.d\.ts$/
]
},
{
test: /\.html$/,
loader: 'html-loader'
},
// to-string-loader is for css loaded by angular components
// .... and loading angular css work as expected.
{ test: /\.css$/, loaders: ['to-string-loader', 'css-loader'] },
{
test: /\.scss$/, // I'd like so much sass work but guess what... it doesn't!
use: ['to-string-loader', 'css-loader', 'sass-loader']
},
// Because phaser and its dependencies are not made for TypeScript and webpack
{ test: /pixi\.js/, use: [{loader: 'expose-loader', options: 'PIXI'}] },
{ test: /phaser-split\.js$/, use: [{loader: 'expose-loader', options: 'Phaser'}] },
{ test: /p2\.js/, use: [{loader: 'expose-loader', options: 'p2'}] }
]
},
plugins: [
new webpack.ContextReplacementPlugin(
// The (\\|\/) piece accounts for path separators in *nix and Windows
// For Angular 5, see also https://github.com/angular/angular/issues/20357#issuecomment-343683491
/\#angular(\\|\/)core(\\|\/)esm5/,
helpers.root('src'), // location of your src
{
// your Angular Async Route paths relative to this root directory
}
),
new CleanWebpackPlugin([distDir]),
new HtmlWebpackPlugin({
template: 'src/index.html',
chunksSortMode: function(a, b) {
// set the load order !
var order = ["polyfills", "app"];
return order.indexOf(a.names[0]) - order.indexOf(b.names[0]);
}
})
]
};
And here is webpack.prod.js configuration:
module.exports = merge(common, {
devtool: 'source-map',
plugins: [
// stops the build if there is an error
new webpack.NoEmitOnErrorsPlugin(),
new UglifyJSPlugin({sourceMap: true}),
// extracts embedded css as external files, adding cache-busting hash to the filename
new ExtractTextPlugin('[name].[hash].css'),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
});
When I run webpack --config config/webpack.prod.js the global CSS is not load, there is no error. Just no CSS.
Feel free to explain also how to load SCSS because it doesn't work even in development mode for me.
Thanks!
I finally make it work. So here is the changes I made:
1) The path to style.css is now ignored in css/scss clauses.
{
exclude: path.resolve(__dirname, '../src/styles'),
test: /\.css$/, loaders: ['to-string-loader', 'css-loader']
},
{
exclude: path.resolve(__dirname, '../src/styles'),
test: /\.scss$/,
use: ['to-string-loader', 'css-loader', 'sass-loader']
}
2) The I added a new entry file for the CSS
entry: {
'polyfills': './src/polyfills.ts',
'app': './src/main.ts',
'css': './src/styles/main.css'
}
3) It works because I also configured a new rule that uses the ExtractTextPlugin
{
test: /\.css$/,
exclude: path.resolve(__dirname, '../src/app'),
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
}
Notice that this works also because the prod configuration specify new ExtractTextPlugin('[name].[hash].css') as plugin. (it means you need to add it in the common configuration to avoid any error in dev environment)
I Think you need to use angular-cli where you can set the custom css url in angular-cli.JSON like as below :
"styles": [
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"../node_modules/font-awesome/css/font-awesome.min.css"
],
more global styles can be set in .angular-cli.json, it maybe looks like this:
...
"apps": [
{
...
"styles": [
"app/core/preloader/preloader.scss",
"styles.scss"
],
...
}
]
...
in app section, you should found that more global assets/scripts can be set here.
more about .angluar-cli.json is here
In a nutshell, I am trying to output my css assets using the extract-text-webpack-plugin. I would expect that the bootstrap loader would spit out a bootstrap.css but this is not the case. I'm thinking I might have to add a include 'webpack-loader/path/to/css' in my app.js, but something about that feels chintzy and against the purpose of webpack.
Below is the most minimal webpack.config.js I can create that represents the issue. The configuration assumes that the webpack.bootstrap.config.js and .bootstraprc files are located in the same directory as the webpack.config.js
const path = require("path");
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const bootstrapEntryPoints = require('./webpack.bootstrap.config');
const extractCssPlugin = new ExtractTextPlugin({
filename : '[name].css'
});
module.exports = {
entry : {
app : "./src/js/app.js",
bootstrap : bootstrapEntryPoints.dev
},
output : {
path : path.resolve(__dirname, 'dist'),
filename : "[name].bundle.js"
},
module : {
rules : [
{ test: /\.css$/, use : extractCssPlugin.extract({use : [{loader: "css-loader"}]})},
{ test: /\.(woff2?|svg)$/, loader: 'url-loader?limit=10000' },
{ test: /\.(ttf|eot)$/, loader: 'file-loader' },
]
},
devServer : {
contentBase : path.join(__dirname, "dist"),
hot : true,
},
plugins : [
extractCssPlugin,
],
};
NOTES :
bootstrapEntryPoints.dev resolves to 'bootstrap-loader'. Meaning that my bootstrap entry point looks like entry : {..., bootstrap : 'bootstrap-loader'}
Solution - I set the extractStyles variable in the .bootstraprc to true. I can now sleep with peace.
I want to use webpack, to compile a style.less file to a module.css file.
I have found https://github.com/webpack-contrib/less-loader as a very popular package, which however does not seem to work for me, since I really need to create that module.css file.
So how can I do that with webpack?
Found the solution myself. The following webpack.config.js snippet works for me:
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = function(env) {
return {
...
module: {
loaders: [
{
test: /.*\.less$/,
loader: ExtractTextPlugin.extract({
loader:[ 'css-loader', 'less-loader' ],
fallbackLoader: 'style-loader'
})
}
]
},
plugins: [
new ExtractTextPlugin({ filename: 'module.css', disable: false, allChunks: true })
]
};
};
Where ... is a placeholder for other parts of the config, which are not relevant here.