With Webpack, there is support for code splitting to different bundles. One of the options is to specify a set of modules you would like to choose as a split point.
Taken from here:
var webpack = require("webpack");
module.exports = {
entry: {
app: "./app.js",
vendor: ["jquery", "underscore", ...],
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendor", /* filename= */"vendor.bundle.js")
]
};
This shows how to split out modules like jquery. However for some javascript libraries that aren't in node_modules that may exist in a more traditional setup like:
/src
/lib
/vendor
/fooLibrary
fooLibrary.js
fooLibrary.css
What I would like is to move these files into the vendor bundle but cannot work out how to specify these files in the vendor entry point.
You can set abs path to vendor lib
var webpack = require("webpack");
module.exports = {
entry: {
app: "./server.js",
vendor: ["/mylib/"],
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendor", /* filename= */"vendor.bundle.js")
]
};
and webpack build lib from abs path to vendor bundle.
But import worked only if index.js exist, so before you should rename vendor file module to index.js with webpack copy plugin or use any tasks script for instance gulp task.
Related
We want to migrate from gulp to webpack on a rather big and old website. Gulp just concat and minify JS & CSS files at the moment. I want to migrate to webpack because another front dev made some react modules that are compiled by browserify cmd in another folder:
we work in a webapp/ folder, minified files are located here :
js/app.min.js
jslib/vendors.min.js
css/app.min.css
sources files are :
js/
file1.js
file2.js
...
jslib/
jquery-1.11.2.min.js
jquery.fancybox.js
...
jquery.very-old-dependency-not-on-npm.min.js
css/
style.css
extra.css
my goal is to keep this file split for javascript by using two files, app.js and vendors.js. These 2 files should be, ideally, ES6 files that import other files.
Actually i'm looking for a way to do a simple concatenation / minification of JS files through the 2 es6 files with imports. Webpack is checking for dependencies and to overcome the "jquery is not defined" errors i added the webpack.providePlugin and the resolve.alias part in webpack.config. But this loads jquery in my app.min.js file and i don't want it for performance purposes. I'm aware that all libs should be npm installed and required/imported in es6 context for an optimized webpack use, but some old jquery libs are not available on npm in the version i want so i have to go with the files already in the project.
vendors.js :
import "./jquery-1.11.2.min.js";
import "./jquery.fancybox.js"
app.js :
import "./file1.js"
import "./file2.js"
webpack.config.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: {
'/../../js/app': path.resolve(__dirname + '/../../js/app.js'),
'/../../jslib/vendors': path.resolve(__dirname + '/../../jslib/vendors.js'),
},
output: {
path: path.resolve(__dirname),
filename: '[name].min.js',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
}),
],
resolve: {
alias: {
jquery: path.resolve(__dirname+'/../../jslib/jquery-1.11.2.min.js')
},
},
}
all my paths are ok (the folder location of the current gulp / future webpack is not in assets folder ) and webpack is successfully running, i just want to find a clean way to perform a simple concat / minify without including jquery in my app file before going further.
Here is an example of using jquery in an html file external
As for the names of app and vendors, you must change this part
entry: {
'/../../js/app': path.resolve(__dirname + '/../../js/app.js'),
'/../../jslib/vendors': path.resolve(__dirname + '/../../jslib/vendors.js'),
},
for this
entry: {
app: path.resolve(__dirname + '/../../js/app.js'),
vendors: path.resolve(__dirname + '/../../jslib/vendors.js'),
},
Do not add jquery to import if you want it to be added from outside. Remove jquery from vendors.js
I hope I helped.
I have a React application, and in my application I'm relying on react-scripts, so the build command is defined like this "build": "react-scripts build", and it works all fine. Now, the point is that inside my src directory I have a JS file called wrapper.js, which is a standalone file, and it is pure JS, no React stuff, but it uses ES6 and some newer features. So, what I want to do is that, I want create a new command, which will transpile and minify this file and will create a standalone copy of it. I thought to use webpack and I created a webpack.config.js file in the root of my project, which looks like this:
const path = require('path');
const MinifyPlugin = require('babel-minify-webpack-plugin');
module.exports = {
mode: 'production',
output: {
path: __dirname + 'build',
publicPath: '/build/',
filename: 'wrapper.js',
},
module: {
rules: [
{
test: /\.js$/,
include: [
path.resolve(__dirname, 'src', 'wrapper.js')
],
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
}
]
},
plugins: [
new MinifyPlugin()
]
};
And I added the following to my package.json file "wrapper": "webpack". Now, when I run npm run-scripts wrapper, it executes the webpack command, but it throws error. The output looks like this:
> webpack
Hash: 0aa67383ec371b8b7cd1
Version: webpack 4.19.1
Time: 362ms
Built at: 04/06/2019 10:54:46 AM
1 asset
Entrypoint main = wrapper.js
[0] ./src/index.js 223 bytes {0} [built] [failed] [1 error]
ERROR in ./src/index.js 22:4
Module parse failed: Unexpected token (22:4)
You may need an appropriate loader to handle this file type.
|
| ReactDOM.render(
> <Root />,
| document.getElementById('root'),
| );
What I see is that the problem is that webpack also tries to transpile and minify other files in my src directory, because it seems it has hit my React app's index.js file. How can I exclude everything? Or more precisely, how can I tell webpack to transpile and minify only the file /src/wrapper.js, and not to touch anything else at all?
Lighter weight alternative could be to create a script in your package.json and use babel-minify, https://babeljs.io/docs/en/babel-minify
package.json
{
...
"scripts": : {
"minify": "minify wrapper.js --out-file wrapper.min.js --mangle.keepClassName"
}
...
}
Add entry object to your webpack.config.js.
module.exports={
entry: './src/wrapper.js',
...
}
webpack points the entry object by default to ./src/index.js.
So if you don't override entry object, webpack will bundle the file in ./src/index.js
Update
To point to a output directory properly
output: {
filename: 'wrapper.js',
path: path.resolve(__dirname, 'build')
}
I am new to webpack and attempting to learn it. I have been trying to copy my vendor js files and custom jquery scripts from src to dist using webpack. I have tried but I couldn't find any way.
So this is how my folder structure is:
Project_root_folder
node_modules/
package.json
src/
app/
app.js
img/
img1.png
css/
main.scss
js/
custom_slick.js
main.js
plugins/
jquery.min.js
slick.min.js
index.pug
about.pug
contact.pug
dist/
webpack.config.js
My webpack.config file
var path = require("path"),
src = path.resolve(__dirname, "src"),
dist = path.resolve(__dirname, "dist"),
webpack = require("webpack"),
HtmlWebpackPlugin = require("html-webpack-plugin"),
HtmlWebpackPugPlugin = require('html-webpack-pug-plugin'),
ExtractTextPlugin = require("extract-text-webpack-plugin"),
extractPlugin = new ExtractTextPlugin({
filename: "css/main.css"
});
module.exports = {
entry: src + "/app/app.js",
output: {
path: dist,
filename: "bundle.js",
publicPath: "/"
},
module: {
rules: [
{ //Convert .pug to .html
test: /\.pug$/,
loaders: ['file-loader?name=[name].html', 'pug-html-loader?pretty&exports=false']
},
{
test: /\.scss$/, //convert .scss to .css
use: extractPlugin.extract({
use: ["css-loader", "sass-loader?minimize=true"]
})
},
{
test: /..\js\$\.js$/, // move all .js files in js folder
use: [
{
loader: "file-loader",
options: {
name: "[name].js",
outputPath: "js/"
}
}
]
},
{
test: /..\js\plugins\.js$/,
use: [
{
loader: "file-loader",
options: {
name: "js/plugins/[name].js",
outputPath: "js/plugins/"
}
}
]
}
]
},
plugins: [
extractPlugin
]
}
App.js file
import '../css/main.scss';
require.context('../js/', true, /\.js$/); //require all js files in js folder
require.context('../js/plugins/', true, /\.js$/); // all js files in plugins folder which is inside js folder
function requirAll (r) { r.keys().forEach(r); }
requireAll(require.context('../', true, /\.pug$/));
Also when I run this config file, I noticed that only the script files with a suffix "-js" get copied and not any other js files included in js/ folder for example filename "main.js" doesn't get copied but if it were named "main-js.js" then it gets copied into my dist folder, and I am unable to copyfiles from plugins/ folder. I am unable to understand this.
I have tried every possible solution I could come across over Stack Overflow, GitHub and similar websites but none were helpful. Also I found webpack to be extremely confusing. Before moving to webpack, I had been using Gulp which I found a lot more helpful. I came across webpack and want to learn it but I am finding it extremely difficult.
Try to use Copy Webpack Plugin in order to copy files between folders.
I'm not sure the reason why you want to copy js files, webpack works like a tree dependency solver, so it should get an entry point (of the tree) and create a bundle that has the entire tree of dependencies.
What I want is to bundle my JavaScript vendor files in a specific order via CommonsChunkPlugin from Webpack.
I'm using the CommonsChunkPlugin for Webpack. The usage from the official documentation is straight forward and easy. It works as intended but I believe the plugin is bundling my files in alphabetical order (could be wrong). There are no options for the plugin to specify the order they should be bundled.
Note: For those who are not familiar with Bootstrap 4, it currently
requires a JavaScript library dependency called Tether.
Tether must be loaded before Bootstrap.
webpack.config.js
module.exports = {
entry: {
app: './app.jsx',
vendor: ['jquery', 'tether', 'bootstrap', 'wowjs'],
},
output: {
path: __dirname + '/dist',
filename: 'bundle.js',
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.bundle.js'
}),
new webpack.optimize.UglifyJsPlugin(),
],
};
Two things are happening here:
vendor.bundle.js contains bootstrap, jquery, tether,
wowjs
bundle.js contains the rest of my application
Bundling order:
correct: jquery, tether, bootstrap, wowjs
incorrect: bootstrap, jquery, tether, wowjs
Notice in my webpack.config.js I ordered them exactly as they should but they are bundled in the incorrect order. It doesn't matter if I rearrange them randomly the result is the same.
After I use Webpack to build my application, the vendor.bundle.js shows me the incorrect order.
I know they're bundled incorrectly cause Chrome Dev. Tools tell me there are dependency issues. When I view the file through the tool and my IDE, it is bundled in the incorrect order.
My other approach also resulted in the same issue
I also tried import and require in my entry file (in this case, app.jsx) without the use of the CommonChunkPlugin and that also loads my JavaScript libraries in alphabetical order for some reason.
webpack.config.js
module.exports = {
entry: './app.jsx',
output: {
path: __dirname + '/dist',
filename: 'bundle.js',
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
],
};
app.jsx (entry)
import './node_modules/jquery/dist/jquery.min';
import './node_modules/tether/dist/js/tether.min';
import './node_modules/bootstrap/dist/js/bootstrap.min';
import './node_modules/wowjs/dist/wow.min';
or
require('./node_modules/jquery/dist/jquery.min');
require('./node_modules/tether/dist/js/tether.min');
require('./node_modules/bootstrap/dist/js/bootstrap.min');
require('./node_modules/wowjs/dist/wow.min');
The result?
Bootstrap > jQuery > Tether > wowjs
How do I load my vendor files in the correct order?
Success!
webpack.config.js
module.exports = {
entry: {
app: './app.jsx',
vendor: [
"script-loader!uglify-loader!jquery",
"script-loader!uglify-loader!tether",
"script-loader!uglify-loader!bootstrap",
"script-loader!uglify-loader!wowjs",
]
},
output: {
path: __dirname + '/dist',
filename: 'bundle.js',
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.bundle.js'
}),
new webpack.optimize.UglifyJsPlugin(),
],
};
What magic is happening here?
Webpack creates vendor.bundle.js by minifying & bundling my vendor
files which now execute in the global context.
Webpack creates bundle.js with all of its application code
entry file (app.jsx in this case)
import './script';
This script is just custom JavaScript that uses jQuery, Bootstrap, Tether and wowjs. It executes after vendor.bundle.js, allowing it to run successfully.
A mistake I made trying to execute my script.js was that I thought it had to be in the global context. So I imported it with script-loader like this: import './script-loader!script';. In the end, you don't need to because if you're importing through your entry file it will end up in the bundle file regardless.
Everything is all good.
Thanks #Ivan for the script-loader suggestion. I also noticed that the CommonsChunkPlugin was pulling the non-minified vendor versions so I chained uglify-loader into the process.
Although, I do believe some .min.js are created differently to get rid of extra bloat. Though that is for me to figure out. Thanks!
You can try https://webpack.js.org/guides/shimming/#script-loader - it looks like it will execute scripts in order and in global context.
Worked with htmlWebpackPlugin from official tutorials and switched the order form entry key. ( vendor then app )
In webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
vendor: [
'angular'
],
app: [
'./src/index.js',
'./src/users/users.controller.js',
'./src/users/users.directive.js',
]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: './src/index-dev.html'
}),
new webpack.NamedModulesPlugin()
...
}
Now in the generated index.html file I have the correct order
<script src='vendor.bundle.js'></script>
<script src='app.bundle.js'></scrip
This worked for me https://www.npmjs.com/package/webpack-cascade-optimizer-plugin
const CascadeOptimizer = require('webpack-cascade-optimizer-plugin');
module.exports = {
entry: {
app: './app.jsx',
vendor: ['jquery', 'tether', 'bootstrap', 'wowjs'],
},
output: {
path: __dirname + '/dist',
filename: 'bundle.js',
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.bundle.js'
}),
new webpack.optimize.UglifyJsPlugin(),
new CascadeOptimizer({
fileOrder: ['jquery', 'tether', 'bootstrap', 'wowjs']
})
],
};
I'm currently using Webpack to pack our Angular2 application and i'm facing a problem.
I've read several documentations but I can't achieve how to copy some files in my output directory using the file loader.
Here is my current file hierarchy :
config
| - webpack.common.js
app
|- static
| - css
| - ...
| - fonts
| - ...
| - img
| - someimage.png
| - anotherimage.png
|- main.ts
and the (full) webpack.common.js :
var path = require("path")
var webpack = require("webpack")
var ExtractTextPlugin = require("extract-text-webpack-plugin")
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
app: './app/main.ts',
},
output: {
filename: 'js/[name].js',
path:'./built',
chunkFilename: 'bundles/[id].chunk.js'
},
module: {
loaders: [
{
test: /\.ts$/,
loader: 'ts',
exclude:'./out/'
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
include: [
path.resolve(__dirname, '/app/static/img/'),
],
loader: 'file?name=[path][name].[ext]&context=./src',
}
]
},
resolve: {
extensions: ['', '.js', '.ts', '.gif']
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
]
}
To execute webpack I play the command :
webpack --config Config/webpack.common.js --bail
The ts file are correctly transpilled into javascript and copied into the output directory, the index.html file is also present but there is none of my image files.
I think there is something wrong in my configuration file but I can't see what. I'm banging my head on it fore many hours so any help will be much appreciated.
Thank you
Creating separate entry point for images may not be what you want, depending on how you build CSS part of the project. As alternative you can copy static files with copy-webpack-plugin or grunt / gulp task.
You should use url-loader to load images. Sample code is given below.
{
module: {
loaders: [
{ test: /\.(jpe?g|png|gif|svg)$/i, loader: 'url?limit=10000!img?progressive=true' }
]
}
}
Are you referring the gif files or corresponding css/sass files inside your entry js file.
entry: {
app: './app/main.ts',
}
Webpack will load all the files which have a reference in the entry point. If all your files are not in one entry point. Then you can add multiple entry points as shown below.
entry: {
app: './app/main.ts',
image: './app/something.ts'
}
Also, i would put webpack.config.js file directly in the root directory to have better access to the whole ecosystem. Try moving it from config folder to root folder.