webpack - splitting files and create 2 bundle - javascript

I'm try to achieve the following target using webpack
in brief I have 2 entry point:
App.js and App2.js
App1.js have a dependency with App1def.js
App2.js have dependency with App2def0x.js files
Cats.js is used by App1.js and App2.js
all appx.js files have also a dependency with Jquery and babel-polyfill
I'd like to compile in:
Vendor.min.js contaning jquery, babel-polyfill (shim)
Common.min.js containg Cats.js (the common file used by appx.js)
App1.boundle.js containing app1def.js
App2.boundle.js containing app2def01.js app2def02.js
my webpack config is here:
var webpack = require("webpack");
const createVendorChunk = require('webpack-create-vendor-chunk');
module.exports = {
entry: {
app:"./src/js/app.js",
app2:"./src/js/app2.js"
},
output: {
path: './bin',
filename:"[name].bundle.js",
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
},
resolve: {
extensions: ['', '.js', '.es6']
},
plugins: [
/*
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "vendor.min.js",
minChunks: Infinity
})
*/
createVendorChunk({
name:"vendor.min.js"
}),
createVendorChunk({
name:"common.min.js",
chunks:["common"]
}),
]
};
complete project is here : https://github.com/mydiscogr/webpack-babel-config/

can you try this?
entry: {
app:"./src/js/app.js",
app2:"./src/js/app2.js"
vendor: [
'jquery',
'moment',
'lodash',
'some other vendor'
]
},
output: {
path: './bin',
filename:"[name].bundle.js",
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
},
resolve: {
extensions: ['', '.js', '.es6']
},
plugins: [
// it moves cat.js to common.js
new webpack.optimize.CommonsChunkPlugin({
name: 'Common',
chunks: ['App1', 'App2']
}),
// some third party libraries (eg: jquery, moment) when used in App1, App2, and Common moves to vendor.js
new webpack.optimize.CommonsChunkPlugin({
name: 'Vendor',
minChunks: Infinity
}
// Just Other Tricks!!
// Delete 2 CommonsChunkPlugin option above and add this
new webpack.optimize.CommonsChunkPlugin({
// The order of this array matters
names: ['Common', 'Vendor'],
minChunks: 2
})
]
let me know if it works

Related

"Can't resolve 'syncfusion-javascript'" Webpack - Aurelia

I'm trying to integrate Syncfusions' Js library with an Aurelia project using the Aurelia Syncfusion Bridge, but i'm getting the following error when trying to load the plugin into my vendor package.
ERROR in dll vendor
Module not found: Error: Can't resolve 'syncfusion-javascript' in 'C:\Users\Liam\Downloads\aurelia-webpack1333503894'
# dll vendor
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const { AureliaPlugin, ModuleDependenciesPlugin } = require('aurelia-webpack-plugin');
const bundleOutputDir = './wwwroot/dist';
module.exports = (env) => {
const isDevBuild = !(env && env.prod);
return [{
stats: { modules: false },
entry: { 'app': 'aurelia-bootstrapper' },
resolve: {
extensions: ['.ts', '.js'],
modules: ['ClientApp', 'node_modules'],
},
output: {
path: path.resolve(bundleOutputDir),
publicPath: 'dist/',
filename: '[name].js'
},
module: {
rules: [
{ test: /\.ts$/i, include: /ClientApp/, use: 'ts-loader?silent=true' },
{ test: /\.html$/i, use: 'html-loader' },
{ test: /\.css$/i, use: isDevBuild ? 'css-loader' : 'css-loader?minimize' },
{ test: /\.(png|jpg|jpeg|gif|cur|svg)$/, use: 'url-loader?limit=25000' },
{ test: /\.woff2(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader', query: { limit: 10000, mimetype: 'application/font-woff2' } },
{ test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader', query: { limit: 10000, mimetype: 'application/font-woff' } },
{ test: /\.(ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader' },
]
},
plugins: [
new webpack.DefinePlugin({ IS_DEV_BUILD: JSON.stringify(isDevBuild) }),
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
}),
new AureliaPlugin({ aureliaApp: 'boot' }),
].concat(isDevBuild ? [
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(bundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
new webpack.optimize.UglifyJsPlugin()
])
}];
}
webpack.config.js
var path = require('path');
var webpack = require('webpack');
const { AureliaPlugin, ModuleDependenciesPlugin } = require('aurelia-
webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var extractCSS = new ExtractTextPlugin('vendor.css');
module.exports = ({ prod } = {}) => {
const isDevBuild = !prod;
return [{
stats: { modules: false },
resolve: {
extensions: ['.js']
},
module: {
loaders: [
{ test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, loader: 'url-loader?limit=100000' },
{ test: /\.css(\?|$)/, loader: extractCSS.extract([isDevBuild ? 'css-loader' : 'css-loader?minimize']) }
]
},
entry: {
vendor: [
'aurelia-event-aggregator',
'aurelia-fetch-client',
'aurelia-framework',
'aurelia-history-browser',
'aurelia-logging-console',
'aurelia-pal-browser',
'aurelia-polyfills',
'aurelia-route-recognizer',
'aurelia-router',
'aurelia-templating-binding',
'aurelia-templating-resources',
'aurelia-templating-router',
'bootstrap',
'bootstrap/dist/css/bootstrap.css',
'jquery',
"aurelia-syncfusion-bridge",
"syncfusion-javascript"
],
},
output: {
path: path.join(__dirname, 'wwwroot', 'dist'),
publicPath: 'dist/',
filename: '[name].js',
library: '[name]_[hash]',
},
plugins: [
extractCSS,
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
new webpack.DllPlugin({
path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'),
name: '[name]_[hash]'
}),
new ModuleDependenciesPlugin({
"aurelia-syncfusion-bridge": ["./grid/grid", "./grid/column"],
}),
].concat(isDevBuild ? [] : [
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } })
])
}]
};
Thanks for your interest towards Syncfusion controls.
We recommend you to configure aurelia-syncfusion-bridge resources in webpack.config.js file. Because aurelia-syncfusion-bridge’s resources are traced by aurelia-webpack-plugin and included in app.bundle.
Suppose If we add this plugin in webpack.vendor.js, we need to bundle manually for every additional aurelia-syncfusion-bridge’s resources for proper bundling. Since, we recommend to configure our bridge in webpack.config.js, which will automatically bundle the bridge source along with application bundle.
We have prepared sample for the same and attached below.
Sample
Please let us know if you need further assistance on this.
Thanks,
Abinaya S

How to include Bootstrap into Vue Js webpack template? [duplicate]

Greetings one and all,
I have been playing around with Bootstrap for Webpack, but I'm at the point of tearing my hair out. I have literally gone through loads of blog articles and they either use the 7 months outdated 'bootstrap-webpack' plugin (which, surprisingly does not work out of the box) or.. They include the Bootstrap files through import 'node_modules/*/bootstrap/css/bootstrap.css'.
Surely, there must be a cleaner and more efficient way of going about this?
This is my current webpack.config.js file:
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var autoprefixer = require('autoprefixer');
var path = require('path');
module.exports = {
entry: {
app: path.resolve(__dirname, 'src/js/main.js')
},
module: {
loaders: [{
test: /\.js[x]?$/,
loaders: ['babel-loader?presets[]=es2015&presets[]=react'],
exclude: /(node_modules|bower_components)/
}, {
test: /\.css$/,
loaders: ['style', 'css']
}, {
test: /\.scss$/,
loaders: ['style', 'css', 'postcss', 'sass']
}, {
test: /\.sass$/,
loader: 'style!css!sass?sourceMap'
},{
test: /\.less$/,
loaders: ['style', 'css', 'less']
}, {
test: /\.woff$/,
loader: "url-loader?limit=10000&mimetype=application/font-woff&name=[path][name].[ext]"
}, {
test: /\.woff2$/,
loader: "url-loader?limit=10000&mimetype=application/font-woff2&name=[path][name].[ext]"
}, {
test: /\.(eot|ttf|svg|gif|png)$/,
loader: "file-loader"
}]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '/js/bundle.js',
sourceMapFilename: '/js/bundle.map',
publicPath: '/'
},
plugins: [
new ExtractTextPlugin('style.css')
],
postcss: [
autoprefixer({
browsers: ['last 2 versions']
})
],
resolve: {
extensions: ['', '.js', '.sass'],
modulesDirectories: ['src', 'node_modules']
},
devServer: {
inline: true,
contentBase: './dist'
}
};
I could go and require('bootstrap') (with some way of getting jQuery in it to work), but.. I'm curious to what you all think and do.
Thanks in advance :)
I am not sure if this is the best way, but following work for me well with vue.js webapp. You can see the working code here.
I have included files required by bootstrap in index.html like this:
<head>
<meta charset="utf-8">
<title>Hey</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="/static/bootstrap.css" type="text/css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.3.7/js/tether.min.js" integrity="sha384-XTs3FgkjiBgo8qjEjBk0tGmf3wPrWtA6coPfQDfFEY8AnYJwjalXCiosYRBIBZX8" crossorigin="anonymous"></script>
<script href="/static/bootstrap.js"></script>
</head>
And this works, you can execute the repo. Why I went this way was I had to customise some config in bootstrap so I had to change the variables file and build the code of bootstrap which outputted me bootstrap.js and bootstrap.cssfiles, which I am using here.
There is an alternative way suggested here by using the npm package and a webpack customisation.
First install bootstrap in your project:
npm install bootstrap#4.0.0-alpha.5
And make sure you can use sass-loader in your components:
npm install sass-loader node-sass --save-dev
now go to your webpack config file and add a sassLoader object with the following:
sassLoader: {
includePaths: [
path.resolve(projectRoot, 'node_modules/bootstrap/scss/'),
],
},
projectRoot should just point to where you can navigate to node_packages from, in my case this is: path.resolve(__dirname, '../')
Now you can use bootstrap directly in your .vue files and webpack will compile it for you when you add the following:
<style lang="scss">
#import "bootstrap";
</style>
I highly recommend using bootstrap-loader. You add a config file (.bootstraprc in your root folder) where you can exclude the bootstrap elements you don't want and tell where your variables.scss and bootstrap.overrides.scss are. Define you SCSS variables, do your overrides, add your webpack entry and get on with your life.
I use webpack to build bootstrap directly from .less and .scss files. This allows customizing bootstrap by overriding the source in .less/.scss and still get all the benefits of webpack.
Your code is missing an entry point for any .css/.less/.scss files. You need to include an entry point for the compiled css files. For this entry point, I declare an array with const and then include paths inside the array to the source files I want webpack to compile.
Currently, I'm using bootstrap 3 with a base custom template and also a 2nd custom theme. The base template uses bootstrap .less file styling and it has specific source overrides written in .less files.
The 2nd custom theme uses .sass file styling and has similar overrides to bootstrap's base written in .scss files. So, I need to try to optimize all this styling for production (currently coming in about 400kb but that's a little heavy because we choose to avoid CDN's due to targeting use in China).
Below is a reference webpack.config.js which works to build from .less/.scss/.css files, and also does a few other things like build typescript modules and uses Babel for converting es6/typescript to browser compatible javascript. The output ultimately ends up in my /static/dist folder.
const path = require('path');
const webpack = require('webpack');
// plugins
const ForkTsCheckerNotifierWebpackPlugin = require('fork-ts-checker-notifier-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// take debug mode from the environment
const debug = (process.env.NODE_ENV !== 'production');
// Development asset host (webpack dev server)
const publicHost = debug ? 'http://localhost:9001' : '';
const rootAssetPath = path.join(__dirname, 'src');
const manifestOptions = {
publicPath: `${publicHost}/static/dist/`,
};
const babelLoader = {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
'#babel/preset-env'
]
}
};
const app_css = [
// specific order generally matters
path.join(__dirname, 'src', 'bootstrap-template1', 'assets', 'css', 'fonts', 'Roboto', 'css', 'fonts.css'),
path.join(__dirname, 'node_modules', 'font-awesome', 'css', 'font-awesome.css'),
// This is bootstrap 3.3.7 base styling writtin in .less
path.join(__dirname, 'src', 'bootstrap-template1', 'assets', 'less', '_main_full', 'bootstrap.less'),
// bootstrap theme in .scss -> src\bp\folder\theme\src\scss\styles.scss
path.join(__dirname, 'src', 'bp', 'folder', 'theme', 'src', 'scss', 'styles.scss'),
// back to .less -> 'src/bootstrap-template1/assets/less/_main_full/core.less',
path.join(__dirname, 'src', 'bootstrap-template1', 'assets', 'less', '_main_full', 'core.less'),
// 'src/bootstrap-template1/assets/less/_main_full/components.less',
path.join(__dirname, 'src', 'bootstrap-template1', 'assets', 'less', '_main_full', 'components.less'),
//'src/bootstrap-template1/assets/less/_main_full/colors.less',
path.join(__dirname, 'src', 'bootstrap-template1', 'assets', 'less', '_main_full', 'colors.less'),
// <!-- syntax highlighting in .css --> src/bp/folder/static/css/pygments.css
path.join(__dirname, 'src', 'bp', 'folder', 'static', 'css', 'pygments.css'),
// <!-- lato/ptsans font we want to serve locally --> src/fonts/googlefonts.css'
path.join(__dirname, 'src', 'fonts', 'googlefonts.css'),
// a .css style -> 'src/bp/appbase/styles/md_table_generator.css'
path.join(__dirname, 'src', 'bp', 'appbase', 'styles', 'md_table_generator.css'),
// another .css style -> hopscotch 'src/libs/hopscotch/dist/css/hopscotch.min.css'
path.join(__dirname, 'src', 'libs', 'hopscotch', 'dist', 'css', 'hopscotch.min.css'),
//LAST final custom snippet styles to ensure they take priority 'src/css/style.css',
path.join(__dirname, 'src', 'css', 'style.css')
];
const vendor_js = [
//'core-js',
'whatwg-fetch',
];
const app_js = [
// a typescript file! :)
path.join(__dirname, 'src', 'typescript', 'libs', 'md-table', 'src', 'extension.ts'),
// base bootstrap 3.3.7 javascript
path.join(__dirname, 'node_modules', 'bootstrap', 'dist', 'js', 'bootstrap.js'),
path.join(__dirname, 'src', 'main', 'app.js'),
// src/bootstrap-template1/assets/js/plugins/forms/styling/uniform.min.js'
path.join(__dirname, 'node_modules', '#imanov', 'jquery.uniform', 'src', 'js', 'jquery.uniform.js'),
// src/bootstrap-template1/assets/js/plugins/ui/moment/moment.min.js'
];
function recursiveIssuer(m) {
if (m.issuer) {
return recursiveIssuer(m.issuer);
} else if (m.name) {
return m.name;
} else {
return false;
}
}
module.exports = {
context: process.cwd(), // to automatically find tsconfig.json
// context: __dirname,
entry: {
app_css,
vendor_js,
app_js,
},
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: `${publicHost}/static/dist/`,
chunkFilename: '[id].[hash:7].js',
filename: '[name].[hash:7].js'
},
resolve: {
extensions: [".webpack.js", ".web.js",".tsx", ".ts", ".js", ".css"],
alias: {
jquery$: path.resolve(__dirname, 'node_modules', 'jquery', 'dist', 'jquery.js'),
}
},
target: "web",
devtool: 'source-map',
devServer: {
// this devserver proxies all requests to my python development server except
// webpack compiled files in the `/static/dist` folder
clientLogLevel: 'warning',
contentBase: path.join(__dirname, './src'),
publicPath: 'dist',
open: true,
historyApiFallback: true,
stats: 'errors-only',
headers: {'Access-Control-Allow-Origin': '*'},
watchContentBase: true,
port: 9001,
proxy: {
'!(/dist/**/**.*)': {
target: 'http://127.0.0.1:8000',
},
},
},
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCssAssetsPlugin({})],
splitChunks: {
cacheGroups: {
appStyles: {
name: 'app',
// https://webpack.js.org/plugins/mini-css-extract-plugin/#extracting-css-based-on-entry
test: (m, c, entry = 'app') =>
m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
chunks: 'all',
enforce: true,
},
},
},
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'window.$': 'jquery'
}),
// Strip all locales from moment.js except "zh-cn"
// ("en" is built into Moment and can’t be removed)
new MomentLocalesPlugin({
localesToKeep: ['zh-cn'],
}),
new ForkTsCheckerWebpackPlugin({
tslint: true, useTypescriptIncrementalApi: true
}),
new ForkTsCheckerNotifierWebpackPlugin({ title: 'TypeScript', excludeWarnings: false }),
new MiniCssExtractPlugin({
filename: '[name].[hash:7].css',
chunkFilename: '[id].[hash:7].css',
moduleFilename: ({ name }) => `${name.replace('/js/', '/css/')}.[hash:7].css`
}),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.optimize\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],
},
canPrint: true
}),
new ManifestPlugin({
...manifestOptions
}),
].concat(debug ? [] : [
// production webpack plugins go here
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
}
}),
new ForkTsCheckerWebpackPlugin({
async: false,
useTypescriptIncrementalApi: true,
memoryLimit: 2048
}),
]),
module: {
rules: [
{
// jinja/nunjucks templates
test: /\.jinja2$/,
loader: 'jinja-loader',
query: {
root:'../templates'
}
},
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
use: [
babelLoader,
{
loader: 'ts-loader',
options:
{ // disable type checker - we will use it in
// fork-ts-checker-webpack-plugin
transpileOnly: true
}
}
]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: [
babelLoader
]
},
{
test: /\.(html|jinja2)$/,
loader: 'raw-loader'
},
{
test: /\.(sc|sa|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: debug,
// only use if hmr is not working correctly
// reloadAll: true,
},
},
{
loader: "css-loader",
},
{
loader: "sass-loader"
},
]
},
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: debug,
// only use if hmr is not working correctly
// reloadAll: true,
},
},
{
loader: 'css-loader', // translates CSS into CommonJS
},
{
loader: 'less-loader', // compiles Less to CSS
},
],
},
{
test: /\.(ttf|eot|svg|gif|ico)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[hash:7].[ext]',
context: rootAssetPath
},
},
],
},
{
test: /\.(jpe?g|png)$/i,
loader: 'responsive-loader',
options: {
name: '[path][name].[hash:7].[ext]',
adapter: require('responsive-loader/sharp'),
context: rootAssetPath
}
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader:'url-loader',
options:{
limit: 10000,
mimetype: 'application/font-woff',
// name: ('fonts/[path][name].[hash:7].[ext]'),
name: ('fonts/[name].[hash:7].[ext]'),
}
},
{
test: require.resolve("jquery"),
use:[
{ loader: "expose-loader", options:"$" },
{ loader: "expose-loader", options:"jQuery" },
{ loader: "expose-loader", options:"jquery" }
]
}
]
},
};

Moving from webpack v1 to v2

I'm trying to migrate my code from webpack v1 to v2 and add in the sass-loader, however I get the error
throw new WebpackOptionsValidationError(webpackOptionsValidationErrors);
I'm very confused as to what the final file is supposed to look like:
let webpack = require('webpack');
let path = require('path');
module.exports = {
devtool: 'eval-source-map',
entry: [
'./src/index'
],
module: {
rules: [
{
test: /\.scss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS
]
}],
test: /\.js?$/,
loader: 'babel-loader',
exclude: /node_modules/
},
resolve: {
extensions: ['.js'],
options: {
enforceExtension: false
}
},
output: {
path: path.join(__dirname, '/dist'),
publicPath: '/',
filename: 'bundle.js'
},
devServer: {
contentBase: './dist',
hot: true,
historyApiFallback: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.LoaderOptionsPlugin({
debug: true,
options: {
context: __dirname
}
})
]
};
At the moment the code is a mix of the two versions. I am using webpack version 2.2.1. Thanks.
There are several things you need to change:
Your test: /\.js?$/ and the corresponding loader and exclude should be another object inside the rules array:
module: {
rules: [
{
test: /\.scss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS
]
},
{
test: /\.js?$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
},
resolve.options does not exist, it is just resolve.enforceExtension directly:
resolve: {
extensions: ['.js'],
enforceExtension: false
},
And finally, although it's not an error but just a warning, new webpack.NoErrorsPlugin() is deprecated and has been replaced with:
new webpack.NoEmitOnErrorsPlugin()
Also if you haven't yet, you should have a look at the migration guide from the official docs https://webpack.js.org/guides/migrating/.

Preferred way of using Bootstrap in Webpack

Greetings one and all,
I have been playing around with Bootstrap for Webpack, but I'm at the point of tearing my hair out. I have literally gone through loads of blog articles and they either use the 7 months outdated 'bootstrap-webpack' plugin (which, surprisingly does not work out of the box) or.. They include the Bootstrap files through import 'node_modules/*/bootstrap/css/bootstrap.css'.
Surely, there must be a cleaner and more efficient way of going about this?
This is my current webpack.config.js file:
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var autoprefixer = require('autoprefixer');
var path = require('path');
module.exports = {
entry: {
app: path.resolve(__dirname, 'src/js/main.js')
},
module: {
loaders: [{
test: /\.js[x]?$/,
loaders: ['babel-loader?presets[]=es2015&presets[]=react'],
exclude: /(node_modules|bower_components)/
}, {
test: /\.css$/,
loaders: ['style', 'css']
}, {
test: /\.scss$/,
loaders: ['style', 'css', 'postcss', 'sass']
}, {
test: /\.sass$/,
loader: 'style!css!sass?sourceMap'
},{
test: /\.less$/,
loaders: ['style', 'css', 'less']
}, {
test: /\.woff$/,
loader: "url-loader?limit=10000&mimetype=application/font-woff&name=[path][name].[ext]"
}, {
test: /\.woff2$/,
loader: "url-loader?limit=10000&mimetype=application/font-woff2&name=[path][name].[ext]"
}, {
test: /\.(eot|ttf|svg|gif|png)$/,
loader: "file-loader"
}]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '/js/bundle.js',
sourceMapFilename: '/js/bundle.map',
publicPath: '/'
},
plugins: [
new ExtractTextPlugin('style.css')
],
postcss: [
autoprefixer({
browsers: ['last 2 versions']
})
],
resolve: {
extensions: ['', '.js', '.sass'],
modulesDirectories: ['src', 'node_modules']
},
devServer: {
inline: true,
contentBase: './dist'
}
};
I could go and require('bootstrap') (with some way of getting jQuery in it to work), but.. I'm curious to what you all think and do.
Thanks in advance :)
I am not sure if this is the best way, but following work for me well with vue.js webapp. You can see the working code here.
I have included files required by bootstrap in index.html like this:
<head>
<meta charset="utf-8">
<title>Hey</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="/static/bootstrap.css" type="text/css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.3.7/js/tether.min.js" integrity="sha384-XTs3FgkjiBgo8qjEjBk0tGmf3wPrWtA6coPfQDfFEY8AnYJwjalXCiosYRBIBZX8" crossorigin="anonymous"></script>
<script href="/static/bootstrap.js"></script>
</head>
And this works, you can execute the repo. Why I went this way was I had to customise some config in bootstrap so I had to change the variables file and build the code of bootstrap which outputted me bootstrap.js and bootstrap.cssfiles, which I am using here.
There is an alternative way suggested here by using the npm package and a webpack customisation.
First install bootstrap in your project:
npm install bootstrap#4.0.0-alpha.5
And make sure you can use sass-loader in your components:
npm install sass-loader node-sass --save-dev
now go to your webpack config file and add a sassLoader object with the following:
sassLoader: {
includePaths: [
path.resolve(projectRoot, 'node_modules/bootstrap/scss/'),
],
},
projectRoot should just point to where you can navigate to node_packages from, in my case this is: path.resolve(__dirname, '../')
Now you can use bootstrap directly in your .vue files and webpack will compile it for you when you add the following:
<style lang="scss">
#import "bootstrap";
</style>
I highly recommend using bootstrap-loader. You add a config file (.bootstraprc in your root folder) where you can exclude the bootstrap elements you don't want and tell where your variables.scss and bootstrap.overrides.scss are. Define you SCSS variables, do your overrides, add your webpack entry and get on with your life.
I use webpack to build bootstrap directly from .less and .scss files. This allows customizing bootstrap by overriding the source in .less/.scss and still get all the benefits of webpack.
Your code is missing an entry point for any .css/.less/.scss files. You need to include an entry point for the compiled css files. For this entry point, I declare an array with const and then include paths inside the array to the source files I want webpack to compile.
Currently, I'm using bootstrap 3 with a base custom template and also a 2nd custom theme. The base template uses bootstrap .less file styling and it has specific source overrides written in .less files.
The 2nd custom theme uses .sass file styling and has similar overrides to bootstrap's base written in .scss files. So, I need to try to optimize all this styling for production (currently coming in about 400kb but that's a little heavy because we choose to avoid CDN's due to targeting use in China).
Below is a reference webpack.config.js which works to build from .less/.scss/.css files, and also does a few other things like build typescript modules and uses Babel for converting es6/typescript to browser compatible javascript. The output ultimately ends up in my /static/dist folder.
const path = require('path');
const webpack = require('webpack');
// plugins
const ForkTsCheckerNotifierWebpackPlugin = require('fork-ts-checker-notifier-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// take debug mode from the environment
const debug = (process.env.NODE_ENV !== 'production');
// Development asset host (webpack dev server)
const publicHost = debug ? 'http://localhost:9001' : '';
const rootAssetPath = path.join(__dirname, 'src');
const manifestOptions = {
publicPath: `${publicHost}/static/dist/`,
};
const babelLoader = {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
'#babel/preset-env'
]
}
};
const app_css = [
// specific order generally matters
path.join(__dirname, 'src', 'bootstrap-template1', 'assets', 'css', 'fonts', 'Roboto', 'css', 'fonts.css'),
path.join(__dirname, 'node_modules', 'font-awesome', 'css', 'font-awesome.css'),
// This is bootstrap 3.3.7 base styling writtin in .less
path.join(__dirname, 'src', 'bootstrap-template1', 'assets', 'less', '_main_full', 'bootstrap.less'),
// bootstrap theme in .scss -> src\bp\folder\theme\src\scss\styles.scss
path.join(__dirname, 'src', 'bp', 'folder', 'theme', 'src', 'scss', 'styles.scss'),
// back to .less -> 'src/bootstrap-template1/assets/less/_main_full/core.less',
path.join(__dirname, 'src', 'bootstrap-template1', 'assets', 'less', '_main_full', 'core.less'),
// 'src/bootstrap-template1/assets/less/_main_full/components.less',
path.join(__dirname, 'src', 'bootstrap-template1', 'assets', 'less', '_main_full', 'components.less'),
//'src/bootstrap-template1/assets/less/_main_full/colors.less',
path.join(__dirname, 'src', 'bootstrap-template1', 'assets', 'less', '_main_full', 'colors.less'),
// <!-- syntax highlighting in .css --> src/bp/folder/static/css/pygments.css
path.join(__dirname, 'src', 'bp', 'folder', 'static', 'css', 'pygments.css'),
// <!-- lato/ptsans font we want to serve locally --> src/fonts/googlefonts.css'
path.join(__dirname, 'src', 'fonts', 'googlefonts.css'),
// a .css style -> 'src/bp/appbase/styles/md_table_generator.css'
path.join(__dirname, 'src', 'bp', 'appbase', 'styles', 'md_table_generator.css'),
// another .css style -> hopscotch 'src/libs/hopscotch/dist/css/hopscotch.min.css'
path.join(__dirname, 'src', 'libs', 'hopscotch', 'dist', 'css', 'hopscotch.min.css'),
//LAST final custom snippet styles to ensure they take priority 'src/css/style.css',
path.join(__dirname, 'src', 'css', 'style.css')
];
const vendor_js = [
//'core-js',
'whatwg-fetch',
];
const app_js = [
// a typescript file! :)
path.join(__dirname, 'src', 'typescript', 'libs', 'md-table', 'src', 'extension.ts'),
// base bootstrap 3.3.7 javascript
path.join(__dirname, 'node_modules', 'bootstrap', 'dist', 'js', 'bootstrap.js'),
path.join(__dirname, 'src', 'main', 'app.js'),
// src/bootstrap-template1/assets/js/plugins/forms/styling/uniform.min.js'
path.join(__dirname, 'node_modules', '#imanov', 'jquery.uniform', 'src', 'js', 'jquery.uniform.js'),
// src/bootstrap-template1/assets/js/plugins/ui/moment/moment.min.js'
];
function recursiveIssuer(m) {
if (m.issuer) {
return recursiveIssuer(m.issuer);
} else if (m.name) {
return m.name;
} else {
return false;
}
}
module.exports = {
context: process.cwd(), // to automatically find tsconfig.json
// context: __dirname,
entry: {
app_css,
vendor_js,
app_js,
},
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: `${publicHost}/static/dist/`,
chunkFilename: '[id].[hash:7].js',
filename: '[name].[hash:7].js'
},
resolve: {
extensions: [".webpack.js", ".web.js",".tsx", ".ts", ".js", ".css"],
alias: {
jquery$: path.resolve(__dirname, 'node_modules', 'jquery', 'dist', 'jquery.js'),
}
},
target: "web",
devtool: 'source-map',
devServer: {
// this devserver proxies all requests to my python development server except
// webpack compiled files in the `/static/dist` folder
clientLogLevel: 'warning',
contentBase: path.join(__dirname, './src'),
publicPath: 'dist',
open: true,
historyApiFallback: true,
stats: 'errors-only',
headers: {'Access-Control-Allow-Origin': '*'},
watchContentBase: true,
port: 9001,
proxy: {
'!(/dist/**/**.*)': {
target: 'http://127.0.0.1:8000',
},
},
},
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCssAssetsPlugin({})],
splitChunks: {
cacheGroups: {
appStyles: {
name: 'app',
// https://webpack.js.org/plugins/mini-css-extract-plugin/#extracting-css-based-on-entry
test: (m, c, entry = 'app') =>
m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
chunks: 'all',
enforce: true,
},
},
},
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'window.$': 'jquery'
}),
// Strip all locales from moment.js except "zh-cn"
// ("en" is built into Moment and can’t be removed)
new MomentLocalesPlugin({
localesToKeep: ['zh-cn'],
}),
new ForkTsCheckerWebpackPlugin({
tslint: true, useTypescriptIncrementalApi: true
}),
new ForkTsCheckerNotifierWebpackPlugin({ title: 'TypeScript', excludeWarnings: false }),
new MiniCssExtractPlugin({
filename: '[name].[hash:7].css',
chunkFilename: '[id].[hash:7].css',
moduleFilename: ({ name }) => `${name.replace('/js/', '/css/')}.[hash:7].css`
}),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.optimize\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],
},
canPrint: true
}),
new ManifestPlugin({
...manifestOptions
}),
].concat(debug ? [] : [
// production webpack plugins go here
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
}
}),
new ForkTsCheckerWebpackPlugin({
async: false,
useTypescriptIncrementalApi: true,
memoryLimit: 2048
}),
]),
module: {
rules: [
{
// jinja/nunjucks templates
test: /\.jinja2$/,
loader: 'jinja-loader',
query: {
root:'../templates'
}
},
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
use: [
babelLoader,
{
loader: 'ts-loader',
options:
{ // disable type checker - we will use it in
// fork-ts-checker-webpack-plugin
transpileOnly: true
}
}
]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: [
babelLoader
]
},
{
test: /\.(html|jinja2)$/,
loader: 'raw-loader'
},
{
test: /\.(sc|sa|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: debug,
// only use if hmr is not working correctly
// reloadAll: true,
},
},
{
loader: "css-loader",
},
{
loader: "sass-loader"
},
]
},
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: debug,
// only use if hmr is not working correctly
// reloadAll: true,
},
},
{
loader: 'css-loader', // translates CSS into CommonJS
},
{
loader: 'less-loader', // compiles Less to CSS
},
],
},
{
test: /\.(ttf|eot|svg|gif|ico)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[hash:7].[ext]',
context: rootAssetPath
},
},
],
},
{
test: /\.(jpe?g|png)$/i,
loader: 'responsive-loader',
options: {
name: '[path][name].[hash:7].[ext]',
adapter: require('responsive-loader/sharp'),
context: rootAssetPath
}
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader:'url-loader',
options:{
limit: 10000,
mimetype: 'application/font-woff',
// name: ('fonts/[path][name].[hash:7].[ext]'),
name: ('fonts/[name].[hash:7].[ext]'),
}
},
{
test: require.resolve("jquery"),
use:[
{ loader: "expose-loader", options:"$" },
{ loader: "expose-loader", options:"jQuery" },
{ loader: "expose-loader", options:"jquery" }
]
}
]
},
};

How to improve Webpack performance in Dev Environment?

How do i improve the webpack build time. Presently i am packing around 150 files. and taking around 15 secs(Which is too much time). And majority of time is being eaten up during "optimize chunk assets" which takes around 10 secs. Any way to bring this down to 3-4 secs max.
Or how do i disable the optimize step in webpack. I am not explicitly using any configuration for minifying/uglifying.
This is the Configuration i am using presently::
module.exports = {
context: __dirname,
entry: './js/main.js',
target: 'web',
module: {
loaders: [
{ test: /text!/, loader: 'raw-loader'},
{ test: /backbone/, loader: 'imports-loader?this=>window' },
{ test: /marionette/, loader: 'imports-loader?this=>window' },
{ test: /sprintf/, loader: 'script-loader' },
{ test: /\.css$/, loader: "style!css" },
{ test: /\.scss$/, loader: 'style!css!sass' },
{ test: /\.js$/, loader: 'jsx-loader?harmony' }
]
},
resolveLoader: {
root: path.join(__dirname, 'node_modules'),
alias: {
'text': 'raw'
}
},
output: {
filename: 'bundle.js',
library: 'require',
libraryTarget: 'this'
},
resolve: {
alias: alias,
root: path.join(__dirname, 'node_modules'),
extensions: ['', '.js', '.jsx']
},
externals: {
jquery: 'jQuery'
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'root.jQuery': 'jquery',
'Backbone': 'backbone',
'_': 'underscore',
'Marionette': 'marionette',
'sprintf': 'sprintf'
})
],
devtool: 'source-map'
};
Thanks for the help in Advance.
There are a couple of optimizations you can do with your build.
First, as it is, you are parsing all the files in your node_modules through the jsx loader. You want to exclude them.
loaders: [{
test: /\.js$/,
loader: 'jsx-loader?harmony',
exclude: /node_modules/, // <---
}]
Second, all your vendor files (which don't change during development) are compiled on every file change. That's not very efficient, you should separate the vendor files from the application code by using the CommonsChunkPlugin.
In essence, you have to add:
config.entry = {
app: './js/main.js',
vendor: ['react', 'moment', 'react-router', /* etc. all the "big" libs */],
};
config.output = {
filename: '[name].js', /* will create app.js & vendor.js */
};
config.plugins = [
/* ... */
new webpack.optimize.CommonsChunkPlugin(
/* chunkName= */"vendor",
/* filename= */"vendor.bundle.js"
),
];
Webpack offers many devtools: https://webpack.github.io/docs/configuration.html#devtool
you are using devtools: 'source-map'.
I changed to devtools: 'cheap-eval-source-map' and the chunk asset optimization goes from 4500ms to 306ms, and with devtools: 'eval' goes to 1ms.
Take note that both are not Production Suported, because the final .js file is too big, in my case is 13MB.

Categories

Resources