Related
I have been trying to use webpack for my project. I have successfully got webpack to compile all of my js into one file correctly. But what i need is for it to also get the css. All of my css is in one file so i figured it would be easy but i cant figure it out. I have tried to split it up into 2 phases CSS_CONFIG and JS_CONFIG
const path = require('path');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
var JS_CONFIG = {
entry: path.join(__dirname, 'src/js/main.js'),
resolve: {
alias: {
'/components': path.resolve(__dirname, 'src/components/'),
'/js': path.resolve(__dirname, 'src/js/'),
'/views': path.resolve(__dirname, 'src/views/'),
},
},
optimization: {
minimizer: [
// For webpack#5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
new TerserPlugin(),
//new CssMinimizerPlugin(),
],
},
}
var CSS_CONFIG = {
entry:path.join(__dirname,"src/index.html"),
module: {
rules: [
{
test: /.s?css$/,
use: [],
},
],
},
optimization: {
minimize:true,
minimizer: [
// For webpack#5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
// `...`,
//new CssMinimizerPlugin(),
],
},
plugins: [],
}
module.exports = [JS_CONFIG, CSS_CONFIG];
This seems like it should be pretty straightforward with webpack but I must not be grasping somthing. Can anyone help me out?
I believe that your CSS_CONFIG should look more like this:
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');
const isDevelopment = process.env.NODE_ENV === 'development'
var config = {
module: {},
};
var cssConfig = Object.assign({}, config, {
devtool: 'source-map',
entry: {
main: path.resolve(__dirname, 'public/css/main.scss'),
fonts: path.resolve(__dirname, 'public/css/fonts.scss'),
app: path.resolve(__dirname, 'public/css/app.scss'),
},
output: {
path: path.resolve(__dirname, 'public/css')
},
performance: {
hints: false
},
plugins: isDevelopment ? [] : [
new RemoveEmptyScriptsPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
}),
],
module: {
rules:[
// Extracts the compiled CSS from the SASS files defined in the entry
{
test: /\.scss$/,
use: isDevelopment ?
[
'style-loader',
{
loader: 'css-loader',
options: { sourceMap: true, importLoaders: 1, modules: false },
},
{
loader: 'postcss-loader',
options: { sourceMap: true }
},
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader',
options: { sourceMap: true }
},
]
: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: (resourcePath, context) => {
// publicPath is the relative path of the resource to the context
// e.g. for ./css/admin/main.css the publicPath will be ../../
// while for ./css/main.css the publicPath will be ../
return path.relative(path.dirname(resourcePath), context) + "/";
},
},
},
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: false,
url: false,
},
},
{
loader: 'postcss-loader',
options:
{
postcssOptions:
{
plugins: [
require('postcss-import'),
require('postcss-url')({
url: 'copy',
useHash: true,
hashOptions: { append: true },
assetsPath: path.resolve(__dirname, 'public/assets/')
})
]
}
}
},
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader',
options: { sourceMap: true }
},
]
},
/* you may or may not need this
{
test: /\.(woff(2)?|ttf|eot|svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/',
esModule: false,
}
}
]
},
*/
],
}
});
use runs the loaders in order that they are put in the array. So 'style-loader' needs to be executed first. Here is a simple way of achieving the desired result.
const path = require('path');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');
const isDevelopment = process.env.NODE_ENV === 'development'
var JS_CONFIG = {
entry: {
main: path.resolve(__dirname, 'src/js/main.js'),
css: path.join(__dirname, 'src/css/main.css'),
},
resolve: {
alias: {
'/components': path.resolve(__dirname, 'src/components/'),
'/js': path.resolve(__dirname, 'src/js/'),
'/views': path.resolve(__dirname, 'src/views/'),
},
},
module: {
rules:[
{
test: /\.css$/,
use:['style-loader','css-loader']
},
],
},
};
module.exports = [JS_CONFIG];
How can i ignore the script tag in Html webpack plugin?
Because I have added this
<script src="cordova.js"/>
tag into my index.html template anonymously for my app development.
See my configuration in Webpack.config.js:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "www"),
filename: "./js/build/[name].build.js",
chunkFilename: "./js/build/[name].build.js",
// publicPath: "./js/build/",
},
module: {
rules: [
{
test: /\.m?js$/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "./",
},
},
"css-loader?url=false",
"sass-loader",
],
},
{
test: /\.html$/,
use: ["html-loader"],
},
{
test: /\.(svg|png|jpeg|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "res",
},
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "./css/build/[name].css",
// chunkFilename: "../css/[id].css"
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// new BundleAnalyzerPlugin()
],
// devtool: "inline-source-map",
};
I just wanted to ignore the script on production and I have researched this many times but unfortunately I don't see any solution
So, if I got the problem right, you want to ignore a certain resource when bundling for production.
The html-loader has an option to filter sources based on attribute, attribute value, context file and anything you have available in you webpack.config.js.
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// Assuming you are passing arguments to your webpack config like argv.mode
const PRODUCTION = true;
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "www"),
filename: "./js/build/[name].build.js",
chunkFilename: "./js/build/[name].build.js",
// publicPath: "./js/build/",
},
module: {
rules: [
{
test: /\.m?js$/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "./",
},
},
"css-loader?url=false",
"sass-loader",
],
},
{
test: /\.html$/,
use: {
loader: "html-loader",
options: {
sources: {
urlFilter: (attribute, value, resourcePath) => {
if (PRODUCTION && /cordova.js$/.test(value)) {
return false;
}
return true;
},
}
},
},
},
{
test: /\.(svg|png|jpeg|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "res",
},
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "./css/build/[name].css",
// chunkFilename: "../css/[id].css"
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// new BundleAnalyzerPlugin()
],
// devtool: "inline-source-map",
};
In the html module rule, I added an options property to html-loader with an example how you could ignore a certain resource with urlFilter. Check the html-loader docs on filtering resources
You will need to get a reference to the variables you passed to your cli like --mode eg. line 5-6. (Not in the current example) See webpack docs on env vars.
I'm trying to replace Gulp with WebPAck. I have this WebPack configuration that compiles a Nunjucks template and bundles js code and css code.
Instead of bundling, I'm trying to configure webpack to inject the vendor assets into the index.html header and body.
I looked into a few webpack plugins but it appears none of the work correctly. This is what I have now :
The nunjucks compilation breaks and the individual vendor assets dont get injected.
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const NunjucksWebpackPlugin = require('nunjucks-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const path = require('path');
const nunjuckspages = require('./nunjuckspages');
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = env => {
const devMode = !env || !env.production;
return {
mode: devMode ? 'development' : 'production',
entry: {
main: './src/index.js',
typescript_demo: './src/typescript_demo.ts',
vendor: './src/vendor.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: 'assets/js/[name].js',
library: 'MainModule',
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader'},
{ loader: 'postcss-loader', options: { sourceMap: true } },
'resolve-url-loader',
{ loader: 'sass-loader', options: { sourceMap: true } }
]
},
{
test: /\.ts(x?)$/,
enforce: 'pre',
exclude: /node_modules/,
use: [
{
loader: 'tslint-loader',
options: { /* Loader options go here */ }
}
]
},
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
query: {
presets: [
'#babel/preset-env'
]
}
},
{
loader: 'ts-loader'
}
]
},
{
enforce: 'pre',
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: [
'#babel/preset-env'
]
}
},
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: '/assets/fonts/'
}
}]
}
]
},
stats: {
colors: true
},
devtool: 'source-map',
plugins: [
new NunjucksWebpackPlugin({
templates: nunjuckspages
}),
new MiniCssExtractPlugin({
filename: 'assets/css/[name].css'
}),
/// new StyleLintPlugin(),
new BrowserSyncPlugin({
host: 'localhost',
port: 3000,
server: { baseDir: ['dist'] }
}),
new ExtraWatchWebpackPlugin({
dirs: ['templates']
}),
new CopyWebpackPlugin([
// copyUmodified is true because of https://github.com/webpack-contrib/copy-webpack-plugin/pull/360
{ from: 'assets/**/*', to: '.' },
{ from: 'img/*', to: './img' },
], { copyUnmodified: true }),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
inject: true,
hash: true,
publicPath: '/',
title: 'TEST1',
template: 'templates/_layouts/layout.html',
showErrors: true
}),
]
};
};
The Webpack Bulid runs pretty slow, project background is a community portal developed in Vue.js...
Can anybody tell if there is any potential for improvement and if so, what?
I wonder if the time for the build process of 37401ms can still be changed by changing the codebase?
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const glob = require('glob');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const autoprefixer = require('autoprefixer');
const statsSettings = {
all: false,
modules: true,
maxModules: 0,
errors: true,
warnings: false,
moduleTrace: true,
errorDetails: true,
timings: true,
performance: true,
builtAt: true,
};
const {
rootDir,
srcDir,
assetsDir,
stylesDir,
buildDir,
sitepackageDir,
publicPath,
} = require('./config');
const chunks = glob.sync(path.join(rootDir, srcDir, 'pages/**/index.js'))
.reduce((obj, file) => {
const name = path.basename(path.dirname(file));
return {
...obj,
[name]: file,
};
}, {});
module.exports = env => {
return {
mode: env.production ? 'production' : 'development',
context: path.join(rootDir, srcDir),
entry: chunks,
output: {
path: path.join(rootDir, buildDir),
filename: '[name].js',
publicPath: env.production ? publicPath : '',
},
devtool: env.production ? false : 'cheap-module-eval-source-map',
devServer: {
contentBase: path.join(rootDir, buildDir),
inline: true,
proxy: {
'/api/v0': 'http://localhost:4000',
},
},
watchOptions: {
ignored: env.watch ? 'node_modules' : '',
aggregateTimeout: 300,
},
stats: env.watch ? statsSettings : 'normal',
module: {
rules: [
{
test: /\.vue$/,
include: [
path.join(rootDir, srcDir),
require.resolve('bootstrap-vue'),
],
loader: 'vue-loader',
},
{
test: /\.js$/,
include: [
path.join(rootDir, srcDir),
require.resolve('bootstrap-vue'),
],
loader: 'babel-loader',
},
{
test: /\.(css|scss)$/,
use: [
env.production ? MiniCssExtractPlugin.loader : 'vue-style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
autoprefixer({
browsers: ['>1%', 'last 2 versions', 'not ie < 11'],
}),
],
},
},
{
loader: 'sass-loader',
options: {
includePaths: [
path.join(rootDir, srcDir, stylesDir),
],
},
},
],
},
{
test: /\.(jpg|jpeg|png|gif|webp|svg|eot|otf|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$/,
loader: 'file-loader',
options: {
name: `${assetsDir}/_processed_/[name].[hash:4].[ext]`,
},
},
],
},
optimization: {
runtimeChunk: {
name: '_runtime',
},
splitChunks: {
cacheGroups: {
// we need to figure out if it's worth having a common chunk
// or if each entry chunk should be somewhat self-contained
common: {
chunks: 'initial',
name: '_common',
minChunks: 2,
minSize: 0,
},
vendor: {
test: /node_modules/,
chunks: 'initial',
name: '_vendor',
enforce: true,
},
},
},
},
resolve: {
extensions: ['.js', '.json', '.vue'],
alias: {
'#app': path.join(rootDir, srcDir),
// although we're using single file components that can be pre-compiled,
// we want to dynamically mounting them in the DOM html.
// this is way we need to alias 'vue' to use the runtime + compiler build here.
// see: https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
vue$: 'vue/dist/vue.esm.js',
},
},
plugins: [
new webpack.DefinePlugin({
PAGES: JSON.stringify(Object.keys(chunks)),
}),
new VueLoaderPlugin(),
...plugHtmlTemplates(),
...plugExtractCss(env),
...plugCopyAssets(),
],
};
};
function plugHtmlTemplates () {
return glob.sync(path.join(rootDir, srcDir, 'pages/**/template.html'))
.map(template => {
const name = path.basename(path.dirname(template));
return {
template,
filename: `${name}.html`,
chunks: ['_runtime', '_vendor', '_styles', '_common', name],
};
})
.map(htmlConfig => new HtmlWebpackPlugin(htmlConfig));
}
function plugExtractCss (env) {
if (!env.production) return [];
return [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].css',
}),
];
}
function plugCopyAssets () {
const assetsSrcPath = path.join(rootDir, srcDir, assetsDir);
if (!fs.existsSync(assetsSrcPath)) return [];
return [
new CopyWebpackPlugin([
{ from: assetsSrcPath, to: path.join(rootDir, buildDir, path.basename(assetsDir)) },
// this is required for the icons to be selectable in the backend
{ from: path.join(assetsSrcPath, 'icons/'), to: path.join(rootDir, sitepackageDir, 'Resources/Public/Icons/') },
// this is required for avatars to be available; we must not check them in in fileadmin since they would
// prevent having the dir linked by Deployer during a deployment
{ from: path.join(rootDir, '../packages/users/Resources/Private/Images/Avatars/'), to: path.join(rootDir, buildDir, 'static/avatars/') },
]),
];
}
The question is whether you can improve the performance by using different plugins or summarizing steps...
I have a similar configuration. My configuration built ~33 seconds. I added a cache-loader package and decrease build time to ~17 seconds.
npm install --save-dev cache-loader
config:
rules: [
//rules here
{
test: /\.vue$/,
use: [
{
loader: 'cache-loader',
options: {}
},
{
loader: 'vue-loader',
options: vueLoaderConfig
}
],
},
{
test: /\.js$/,
use: [
{
loader: 'cache-loader',
options: {}
},
{
loader: 'babel-loader'
}
],
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
}
]
I have the following problem when running the webpack dev server:
when I run npm start, it show the following:
➜ directory git:(staging) ✗ npm start
directory #1.0.0 start directory
BUILD_DEV=1 BUILD_STAGING=1 ./node_modules/webpack-dev-server/bin/webpack-dev-server.js
http://localhost:8080/
webpack result is served from /undefined/
content is served from
directory
404s will fallback to /index.html
Hash: 75773622412153d5f921
Version: webpack 1.12.11
Time: 43330ms
I guess the problem might because the following line:
webpack result is served from /undefined/
When I open the browser at http://localhost:8080/, it appear as follow:
Cannot GET /
and there is no thing in the console.
Do you have any ideas for this problem ?
UPDATE: WEBPACK CONFIG FILE
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
const nodeModulesDir = path.resolve(__dirname, 'node_modules');
const deps = [
'moment/min/moment.min.js',
'underscore/underscore-min.js',
];
/* Include SASS path here if you want to this in your sass files:
* #import 'bourbon';
*/
const bourbon = require('node-bourbon').includePaths;
const TARGET = process.env.npm_lifecycle_event;
const ROOT_PATH = path.resolve(__dirname);
const SASS_DEPS = [bourbon].toString();
const BUILD_NUMBER = process.env.CI_BUILD_NUMBER;
const common = {
entry: path.resolve(ROOT_PATH, 'app/index.js'),
output: {
filename: BUILD_NUMBER + '-[hash].js',
path: path.resolve(ROOT_PATH, 'build'),
publicPath: `/${BUILD_NUMBER}/`,
},
module: {
loaders: [
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass?includePaths[]=' + SASS_DEPS],
include: path.resolve(ROOT_PATH, 'app'),
},
{
test: /\.css$/,
loaders: [
'style',
'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
'sass?includePaths[]=' + SASS_DEPS,
'postcss'
],
include: path.resolve(ROOT_PATH),
exclude: /(pure\/grids|Grids).*\.css$/,
},
{
test: /(pure\/grids|Grids).*\.css$/,
loaders: [
'style',
'css',
'sass?includePaths[]=' + SASS_DEPS,
],
include: path.resolve(ROOT_PATH),
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?limit=10000&minetype=application/font-woff',
},
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader',
},
{
test: /\.json$/,
loader: 'json',
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'My App',
template: path.resolve(ROOT_PATH, 'app/index.html'),
inject: 'body',
minify: {
removeComments: true,
collapseWhitespace: true,
},
}),
new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'false')),
__STAGING__: JSON.stringify(JSON.parse(process.env.BUILD_STAGING || 'false')),
__API_HOST__: JSON.stringify(process.env.BUILD_STAGING ? 'my.api' : 'my.api'),
}),
],
resolve: {
alias: {
'styles': path.resolve(ROOT_PATH, 'app/styles'),
},
extensions: ['', '.js', '.jsx', '.json'],
},
postcss: function() {
return [
require('postcss-import'),
require('autoprefixer'),
require('postcss-cssnext'),
]
}
};
if (TARGET === 'start' || !TARGET) {
module.exports = merge(common, {
output: {
filename: '[hash].js',
path: path.resolve(ROOT_PATH, 'build'),
publicPath: '/',
},
devtool: 'eval-source-map',
module: {
loaders: [
{
test: /\.jsx?$/,
loaders: [
'react-hot',
'babel-loader'
],
include: path.resolve(ROOT_PATH, 'app'),
},
],
},
devServer: {
colors: true,
historyApiFallback: true,
hot: true,
inline: true,
progress: true,
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
],
});
} else if (TARGET === 'build' || TARGET === 'builds') {
const config = {
resolve: {
alias: {},
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
include: path.resolve(ROOT_PATH, 'app'),
},
],
noParse: [],
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
minimize: true,
compressor: {
screw_ie8: true,
warnings: false,
},
compress: {
warnings: false,
},
output: {
comments: false,
},
}),
new webpack.optimize.DedupePlugin(),
new webpack.DefinePlugin({
'process.env': { 'NODE_ENV': JSON.stringify(process.env.NODE_ENV) },
}),
],
};
deps.forEach((dep) => {
const depPath = path.resolve(nodeModulesDir, dep);
config.resolve.alias[dep.split(path.sep)[0]] = depPath;
config.module.noParse.push(depPath);
});
module.exports = merge(common, config);
}
Same problem occurred to me when i started using babel-loader > 6.
It was fixed by adding contentBase in webpack dev server configuration.
In my case it looked like this
new WebPackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
contentBase: __dirname + '/public'
}).listen(3000, 'localhost')
I would be great to see your webpack config file to pin point the exact problem, but from the error message, there could be multiple problem
Make sure you are on the right port
Make sure your webpack config has
path and public path setup
Make sure you have contentBase setup as
well
Without seeing your webpack file and more concrete detail, it is quite hard to pinpoint the issue. But you can always go to https://webpack.github.io/docs/webpack-dev-server.html for information on how to set it up.