Webpack optimise and compress CSS and Javascript based on production mode inside webpack.config.js - npm

I have the following NPM scripts inside package.json:
"scripts": {
"start": "cross-env NODE_ENV=development webpack --mode development",
"build": "cross-env NODE_ENV=production webpack --mode production"
},
if I run npm run build (production mode) I want to add optimization (see below) to compress my CSS and Uglify the Javascript. How do I achieve that?
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
if I run npm start I want to watch the files and further the same as production mode except optimization. I am building a Drupal site so I need to build the assets also in development.
My webpack.config.js looks like this now:
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyPlugin = require('copy-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');
const config = {
entry: {
main: "./src/index.js",
courses: "./src/courses.js",
vendor: "./src/vendor.js"
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new MiniCssExtractPlugin({ filename: '[name].css' }),
new CopyPlugin([
{ from: './src/assets/images', to: 'assets/images' },
{ from: './src/assets/icons', to: 'assets/icons' }
]),
],
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { importLoaders: 1 } },
'postcss-loader',
]
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: './assets/fonts',
},
},
}
]
}
};
module.exports = (env, argv) => {
if (argv.mode === 'development') {
//...
}
if (argv.mode === 'production') {
//...
}
return config;
};
How do I build this in?

I fix it by adjusting webpack.config.js like below:
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyPlugin = require('copy-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');
const config = {
//Entry Point
entry: {
main: "./src/index.js",
courses: "./src/courses.js",
vendor: "./src/vendor.js"
},
//Output
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
//Watch
watch: false,
watchOptions: {
ignored: ['node_modules']
},
//Loader
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { importLoaders: 1 } },
'postcss-loader',
]
},
{
//For fonts
test: /\.(woff|woff2|ttf|otf|eot)$/,
use: [
{
//using file-loader too
loader: "file-loader",
options: {
outputPath: "fonts"
}
}
]
}
]
},
//plugin
plugins: [
new MiniCssExtractPlugin({ filename: '[name].css' }),
new CopyPlugin([
{ from: './src/assets/images', to: 'assets/images' },
{ from: './src/assets/icons', to: 'assets/icons' }
]),
],
};
module.exports = (env, argv) => {
if (argv.mode === 'development') {
//...
config.mode = "development";
config.watch = true;
}
if (argv.mode === 'production') {
//...
config.mode = "production";
config.optimization = {
splitChunks: {
chunks: "all"
},
minimize: true,
minimizer: [
new OptimizeCssAssetsPlugin(),
new TerserPlugin({
cache: true
})
]
};
}
return config;
};
If anybody have improvements on above, please let me know.

Related

You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file using Webpack 5.40.0

I am building web version from existing React Native project using react-native-web.
webpack.config.js
const path = require('path');
const webpack = require('webpack'); const HtmlWebpackPlugin =
require('html-webpack-plugin');
const appDirectory = path.resolve(__dirname); const {presets} =
require(`${appDirectory}/babel.config.js`);
const compileNodeModules = [ // Add every react-native package that
needs compiling // 'react-native-gesture-handler', ].map(moduleName
=> path.resolve(appDirectory, `node_modules/${moduleName}`));
const babelLoaderConfiguration = { test: /\.js$|(tsx|jsx)?$/, //
Add every directory that needs to be compiled by Babel during the
build. include: [
path.resolve(__dirname, 'index.web.js'), // Entry to your application
path.resolve(__dirname, 'App.web.tsx'), // Change this to your main App file
path.resolve(__dirname, 'src'),
...compileNodeModules, ], use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets,
plugins: ['react-native-web'],
}, }, };
const svgLoaderConfiguration = { test: /\.svg$/, use: [
{
loader: '#svgr/webpack',
}, ], };
const imageLoaderConfiguration = { test: /\.(gif|jpe?g|png)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
}, }, };
module.exports = { entry: {
app: path.join(__dirname, 'index.web.js'), }, output: {
path: path.resolve(appDirectory, 'dist'),
publicPath: '/',
filename: 'fictionate.me.bundle.js', }, resolve: {
extensions: ['.web.tsx', '.web.ts', '.tsx', '.ts', '.web.js', '.js'],
alias: {
'react-native$': 'react-native-web',
}, }, module: {
rules: [
babelLoaderConfiguration,
imageLoaderConfiguration,
svgLoaderConfiguration,
], }, plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'index.html'),
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
// See: https://github.com/necolas/react-native-web/issues/349
__DEV__: JSON.stringify(true),
}), ], };
babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};
When I am trying to build web, it failed with following issue.
enter image description here
Please help me if someone knows how to fix this issue.

How to fix 'npm : Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.'

I am trying to integrate Vue.js with ASP.Net core mvc project. I was following a certain tutorial but got stuck when I tried to build the npm project.
I got the following error:
'npm : Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.'
Here is my webpack.config.js file
var path = require("path");
var webpack = require("webpack");
var fs = require("fs");
var appBasePath = './Scripts/'; // where the source files are located
var publicPath = '../bundle'; // public path to modify asset urls. eg:
'../bundle' =? 'www.example.com/bundle/main.js'
var bundleExportPath = './wwwroot/bundle/'; //directory to export built files
var jsEntries = {}; // listing to compile
// We search for js files inside basePath folder and make those as entries
fs.readdirSync(appBasePath).forEach(function (name) {
// assumption: modules arre located in seperate directory and each module component is imported to index.js of particular module
var indexFile = appBasePath + name + '/index.js'
if (fs.existsSync(indexFile)) {
jsEntries[name] = indexFile
}
});
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: jsEntries,
output: {
path: path.resolve(__dirname, bundleExportPath),
publicPath: publicPath,
filename: '[name].js'
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'#': path.join(__dirname, appBasePath)
}
},
modules: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
scss: 'vue-style-loader!css-loader!sass-loader', // <style lang="scss">
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax' // <style lang="sass">
}
}
},
{
test: /\.scss$/,
loader: 'style-loader!css-loader!sass-loader'
},
{
test: /\.css$/,
loader: 'style-loader!css-loader'
},
{
test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
loader: 'file-loader'
},
{
test: /\.(png|jpe?g|gif|svg)(\?\S*)?$/,
loader: 'file-loader',
query: {
name: '[name].[ext]?[hash]'
}
}
]
},
devtool: '#source-map', // #eval-source-map
}
module.exports.watch = process.env.WATCH === "true";
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
//https://vue-loader.vuejs.prg/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new UglifyJsPlugin({
"uglifyOptions":
{
compress: {
warnings: false
},
sourceMaps: true
}
}),
]);
}
else if (process.env.NODE_ENV === "dev") {
module.exports.watch = true;
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"development"'
}
}),
]);
}
Any help please?
Ow, just realized that nothing was wrong, it's just a typo (modules instead of module)

Deploy vuejs application for relative path

I'm trying to deploy my vuejs application on relative path. I also add the homepage url in the package.json file but it doesn't work for me. How can i do that. Here are the some extra detail which might be easily understandable for you guy's. You can check this details and let me know if its understandable or not i'll try to add some more details.
Server- Apache
Url- "http://example.cpm/subpath/"
webpack.config.js
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
// plugins
const HtmlWebPackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
// the path(s) that should be cleaned
let pathsToClean = [
'dist'
]
// the clean options to use
let cleanOptions = {
root: __dirname,
verbose: false, // Write logs to console.
dry: false
}
// Webpack uses `publicPath` to determine where the app is being served from.
// In development, we always serve from the root. This makes config easier.
const publicPath = '/';
// Make sure any symlinks in the project folder are resolved:
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
entry: ["babel-polyfill", "./src/index.js"],
output: {
// The build folder.
path: resolveApp('dist'),
// Generated JS file names (with nested folders).
// There will be one main bundle, and one file per asynchronous chunk.
// We don't currently advertise code splitting but Webpack supports it.
filename: 'static/js/[name].[chunkhash:8].js',
chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
// We inferred the "public path" (such as / or /my-project) from homepage.
publicPath: publicPath
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js',
Api: path.resolve(__dirname, 'src/api/'),
Components: path.resolve(__dirname, 'src/components/'),
Constants: path.resolve(__dirname, 'src/constants/'),
Container: path.resolve(__dirname, 'src/container/'),
Views: path.resolve(__dirname, 'src/views/'),
Helpers: path.resolve(__dirname, 'src/helpers/'),
Themes: path.resolve(__dirname, 'src/themes/')
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
contentBase: false,
compress: true,
port: 8080, // port number
historyApiFallback: true,
quiet: true
},
module: {
rules: [
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src')],
options: {
formatter: require('eslint-friendly-formatter')
}
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'static/img/[name].[hash:7].[ext]'
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'media/[name].[hash:7].[ext]'
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'media/fonts/[name].[hash:7].[ext]'
}
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
}
]
},
optimization: {
minimizer: [
// we specify a custom UglifyJsPlugin here to get source maps in production
new UglifyJsPlugin({
cache: true,
parallel: true,
uglifyOptions: {
compress: false,
ecma: 6,
mangle: true
},
sourceMap: true
})
]
},
plugins: [
new FriendlyErrorsWebpackPlugin({
compilationSuccessInfo: {
messages: ['You application is running here http://localhost:8080']
}
}),
new CleanWebpackPlugin(pathsToClean, cleanOptions),
new HtmlWebPackPlugin({
template: "./index.html",
filename: "./index.html",
favicon: './static/favicon.png'
}),
new CopyWebpackPlugin([{
from: 'static',
to: 'static'
}]),
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:8].css",
chunkFilename: "static/css/[name].[contenthash:8].css"
}),
//jquery plugin
new webpack.ProvidePlugin({
$: 'jquery',
jquery: 'jquery',
'window.jQuery': 'jquery',
jQuery: 'jquery'
})
]
}
// Webpack uses publicPath to determine where the app is being served from.
// In development, we always serve from the root. This makes config easier.
const publicPath = '/';
Did you try changing the path to './' ?

NODE_ENV is undefined in express

So I am just getting started in learning webpack(2.2.1) and react and I am encountering a bit of a problem with NODE_ENV. I set it in package.json like so:
"scripts": {
"start": "set NODE_ENV=production&& webpack",
"test": "echo \"Error: no test specified\" && exit 1"
}
Then I put a console.log(process.env.NODE_ENV) into the entry file for webpack to see if it set and it does as expected.
However when I go to run express in a file called server.js in the project's root directory:
const express = require('express');
const path = require('path');
const app = new express;
console.log(process.env.NODE_ENV);
const port = process.env.PORT || 3000;
app.use(express.static('public'));
app.get('/',(req,res)=>{
res.sendFile(path.join(__dirname, "public/index.html"));
});
app.listen(port, ()=>{
console.log("listening...", process.env.NODE_ENV);
});
process.env.NODE_ENV is undefined.
Here is the webpack.config
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const VENDOR_LIBS = ['react', 'react-dom', 'bootstrap', 'jquery'];
module.exports = {
entry: {
bundle: './src/index.js',
vendor: VENDOR_LIBS
},
output: {
path: __dirname + '/public',
filename: '[name].js'
},
module: {
rules: [
{
use: 'babel-loader',
test: /\.(js|jsx)$/,
exclude: /node_modules/
},
{
loader: ['style-loader', 'css-loader'],
test: /.css$/
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10000&mimetype=application/octet-stream'
},
{
loader: 'url?limit=10000!img?progressive=true',
test: /\.(jpe?g|png|gif|svg)$/i
}
]
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jquery: 'jquery',
jQuery: 'jquery'
}),
new webpack.optimize.CommonsChunkPlugin({name: "vendor", filename: "vendor.js"}),
new ExtractTextPlugin("./styles/bootstrap.css"),
new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)})
]
}
Any help would be greatly appreciated.

webpack build css rules have different order then in development

I am not sure if this is a webpack issue, vue-loader for webpack issue or just something that I am doing wrong.
When I am running npm run build to build a distribution for my Vue.js application the CSS rules applied in the dist app are in different order then in my development environment thus my CSS overrides are different and app doesn't render right...
Here is demonstration for one element:
npm run dev - proper render
npm run build - improper render
UPDATE: added webpack config files
webpack.base.conf.js
var path = require('path')
module.exports = {
entry: {
app: './src/main.js'
},
output: {
path: path.resolve(__dirname, '../dist/static'),
publicPath: '/static/',
filename: '[name].js'
},
resolve: {
extensions: ['', '.js', '.vue'],
alias: {
'src': path.resolve(__dirname, '../src')
}
},
resolveLoader: {
root: path.join(__dirname, 'node_modules')
},
module: {
preLoaders: [
{
test: /\.vue$/,
loader: 'eslint',
exclude: /node_modules/
},
{
test: /\.js$/,
loader: 'eslint',
exclude: /node_modules/
}
],
loaders: [
{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/
},
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.scss$/,
loaders: ['style', 'css?sourceMap', 'sass?sourceMap']
},
{
test: /\.(png|jp?g|gif|svg|woff2?|eot|ttf)(\?.*)?$/,
loaders: [
'url?limit=20000&name=[name].[ext]?[hash:7]',
'image-webpack?{progressive:true, optimizationLevel: 7, interlaced: false, pngquant:{quality: "65-90", speed: 4}}'
]
},
{
test: /\.html$/,
loader: 'html'
}
]
},
eslint: {
formatter: require('eslint-friendly-formatter')
},
vue: {
loaders: {
sass: 'style!css!sass?indentedSyntax'
}
},
stylus: {
use: [require('nib')()],
import: ['~nib/lib/nib/index.styl']
}
}
webpack.dev.conf.js
var webpack = require('webpack')
var config = require('./webpack.base.conf')
var HtmlWebpackPlugin = require('html-webpack-plugin')
// eval-source-map is faster for development
config.devtool = '#eval-source-map'
// add hot-reload related code to entry chunks
var polyfill = 'eventsource-polyfill'
var devClient = './build/dev-client'
Object.keys(config.entry).forEach(function (name, i) {
var extras = i === 0 ? [polyfill, devClient] : [devClient]
config.entry[name] = extras.concat(config.entry[name])
})
// necessary for the html plugin to work properly
// when serving the html from in-memory
config.output.publicPath = '/'
config.plugins = (config.plugins || []).concat([
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'src/index.html',
inject: true
})
])
module.exports = config
webpack.prod.conf.js
var webpack = require('webpack')
var config = require('./webpack.base.conf')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
// naming output files with hashes for better caching.
// dist/index.html will be auto-generated with correct URLs.
config.output.filename = '[name].[chunkhash].js'
config.output.chunkFilename = '[id].[chunkhash].js'
// whether to generate source map for production files.
// disabling this can speed up the build.
var SOURCE_MAP = true
config.devtool = SOURCE_MAP ? 'source-map' : false
// generate loader string to be used with extract text plugin
function generateExtractLoaders (loaders) {
return loaders.map(function (loader) {
return loader + '-loader' + (SOURCE_MAP ? '?sourceMap' : '')
}).join('!')
}
// http://vuejs.github.io/vue-loader/configurations/extract-css.html
var cssExtractLoaders = {
css: ExtractTextPlugin.extract('vue-style-loader', generateExtractLoaders(['css'])),
less: ExtractTextPlugin.extract('vue-style-loader', generateExtractLoaders(['css', 'less'])),
sass: ExtractTextPlugin.extract('vue-style-loader', generateExtractLoaders(['css', 'sass'])),
stylus: ExtractTextPlugin.extract('vue-style-loader', generateExtractLoaders(['css', 'stylus']))
}
config.vue = config.vue || {}
config.vue.loaders = config.vue.loaders || {}
Object.keys(cssExtractLoaders).forEach(function (key) {
config.vue.loaders[key] = cssExtractLoaders[key]
})
config.plugins = (config.plugins || []).concat([
// http://vuejs.github.io/vue-loader/workflow/production.html
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new webpack.optimize.OccurenceOrderPlugin(),
// extract css into its own file
new ExtractTextPlugin('[name].[contenthash].css'),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /src/index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: '../index.html',
template: 'src/index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
}
})
])
module.exports = config
What helped me, was tapping into the html plugin config, by adding this to vue.config.js
chainWebpack: config => {
config
.plugin('html')
.tap(args => {
args[0].chunksSortMode = function (chunk1, chunk2) {
const order = ['first', 'second', 'third']
const order1 = order.indexOf(chunk1.names[0])
const order2 = order.indexOf(chunk2.names[0])
return order1 - order2
}
return args
})
},