I am using webpack to create my production bundle for running an express application. I thought the webpack externals field would bundle up the dependencies I required to deploy without having to do a yarn install or an npm install.
My server webpack config looks like this:
const config = merge(common, {
name: 'server',
target: 'node',
externals: readdirSync(path.join(__dirname, '../../node_modules'))
.filter(x => !/\.bin|react-universal-component|require-universal-module|webpack-flush-chunks/.test(x))
.reduce((externals, mod) => {
externals[mod] = `commonjs ${mod}`;
return externals;
}, {});
I can see the following entry for express in the list of externals:
express: 'commonjs express',
But when I try and execute the file with the script that requires the express dependency I get:
Cannot find module 'express'
I thought the whole point of externals was to specify what should be bundled.
I thought the whole point of externals was to specify what should be
bundled.
Is the opposite, from the webpack documentation:
The externals configuration option provides a way of excluding
dependencies from the output bundles. Instead, the created bundle
relies on that dependency to be present in the consumer's environment.
So you don't want express in your externals, because it will actually be excluded from the bundle.
Related
I have setup entries in webpack config as
entry: {
// main: './src/index.js',
analytics: './src/analytics/index.js',
};
since the main entry is commented out I expected some modules not to be included in the bundle but were still being added. It turns out both entries eventually import some stuff from a file that re-exports a lot of the unwanted and wanted modules.
Why aren't such unused exports excluded from the bundle?
After going through the tree-shaking documentation I can confirm that
We use ES2015 module syntax (i.e. import and export).
#babel/preset-env is configured with modules: false, other babel presets we use are #babel/preset-react and #babel/preset-typescript
not sure if sideEffects should be set in package.json as we are not publishing the project as package, I am okay with third-party libraries not being tree-shaken. optimization.sideEffects should be true by default.
production mode is enabled
I have used node to manage dependencies on React apps and the like, in those you use package.json to keep track of libs and use them in your scripts using ES6 import module syntax.
But now I'm working on a legacy code base that uses a bunch of jQuery plugins (downloaded manually and placed in a "libs" folder) and links them directly in the markup using script tags.
I want to use npm to manage these dependencies. Is my only option:
run npm init
install all plugins through npm and have them in package.json
link to the scripts in the node_modules folder directly from the markup:
<script src="./node_modules/lodash/lodash.js"></script>
or is there a better way?
Check out this tutorial for going from using script tags to bundling with Webpack. You will want to do the following: (Do steps 1 and 2 as you mentioned in your question then your step 3 will change to the following 3 steps)
Download webpack with npm: npm install webpack --save-dev
Create a webpack.config.js file specifying your entry file and output file. Your entry file will contain any custom JS components your app is using. You will also need to specify to include your node_modules within your generated Javascript bundle. Your output file will be the resulting Javascript bundle that Webpack will create for you and it will contain all the necessary Javascript your app needs to run. A simple example webpack.config.js would be the following:
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
resolve: {
alias: {
'node_modules': path.join(__dirname, 'node_modules'),
}
}
};
Lastly, add a <script> tag within your main HTML page pointing to your newly generated Javascript bundle:
<script src="dist/my-first-webpack.bundle.js"></script>
Now your web application should work the same as before your refactoring journey.
Cheers
I recommend Parcel js.
Then you only need:
Run npm init
Install dependency, for example npm install jquery
Import with ES6 syntax: import $ from "jquery";
And run with parcel
We are trying to Browserify our node app
Sample File (index.js)
module.exports = {
index: () => 'test',
};
Browserify command
browserify src/index.js > dist/bundle.js --node
If we use a file to require and console
console.log(require('src/index')); // { index: [Function: index] }
console.log(require('dist/bundle')); // { }
Our expectation is that bundle.js would export the same as index.js.
Can anyone point us at what we are doing wrong or missing?
Additional Info
~This is not our app, this is a sample to demonstrate the issue
We are currently sending our entire app zipped to AWS Lambda with the entry point src/index.index and the objective is to just send the bundle.js file and be able to to have the entry point bundle.index
bundle.js
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
module.exports = {
index: () => 'test',
};
},{}]},{},[1]);
You need to use the --standalone flag. If I reproduce the setup you describe in your question and execute:
$ browserify src/index.js --standalone mylib > dist/bundle.js
Then I can run an interactive Node session on it and use the library in the way you expect it to be used:
$ node
> require("./dist/bundle").index()
'test'
The --standalone flag tells Browserify to wrap your code in a UMD stub which allows loading the bundle as CommonJS module, an AMD module, or as a plain script (i.e. does not use a module system). The argument you pass with --standalone indicates what name your library will take in the "plain script" case. So in the example above, if you were to load the library in a browser without any module system, you'd be able to run index as mylib.index().
You can use serverless for this, pretty easy to configure. No need to use browserify cli for this.
Keep following following official documentations to setup serverless cli.
Installation
AWS - Credentials
Quick Start
Once everything is setup and you are able to deploy your lambda functions to AWS using serverless cli. Follow following steps to setup browserify.
Install browserify as a dev dependecy.
Install serverless-plugin-browserifier as a dev dependency.
Add the plugin to your serverless.yml file and set package.individually to true. (Ref)
plugins:
- serverless-plugin-browserifier
package:
individually: true
Note: Personally tried this and is working.
in react using webpack every js files is bundle into a single bundle.js , for my normal html , css, js application for example , i am having 6 libraries. for an example consider
i am using jquery and bootstrap min versions. so if i reference two files the request will be two. so how can i make it into a single file. So there will be a single request.
like when i checked the file size is about in kb's and the request is processed within less that 1 or 2 seconds , like the chrome dev tools shows the time for to load also it parrallely loads the two files.
But how can i bundle the two librarys using webpack and get a single file that i can refer in my application.
i am a beginner to webpack
You need to import them in your entry point file and Webpack will handle the bundling. As you have worked with React, I assume you have basic command line skills.
You can read the Getting Started guide which bundles Lodash like how you are trying to bundle jQuery and Bootstrap.
First of install, ensure that you are installing jQuery, Bootstrap, and any other libraries using npm (or yarn, if you prefer):
# Install Webpack as a dev dependency
npm install webpack webpack-cli --save-dev
# Install dependencies (I've added Popper.js as Bootstrap requires it)
npm install jquery bootstrap popper.js
Create a folder called src and a file inside there called index.js. This is your entry point and Webpack will look for this file unless configured differently. Import the libraries like this:
import $ from 'jquery'
import 'bootstrap'
// Do something with jQuery
$(document).ready(() => console.log('Hello world!'))
Then run Webpack using npx:
npx webpack
A file named main.js should be created in a folder called dist that contains the bundled code. This is your output file. You can use a <script> tag in your HTML file to load this JavaScript:
<!-- assuming your index.html is in the dist folder -->
<script src='main.js'></script>
Once you get here, you can explore more advanced things like importing Bootstrap components individually, minifying code, multiple bundles, transpiling TypeScript, etc.
You will likely need to add a Webpack configuration file very soon as there is only so much that can be done using zero-config mode.
Good practice is to keep two sepearate bundles for the application logic and external libraries and in webpack this can be achieved by the following code,
app.js - appliation index file,
vendors.js - import all external libraries in this file
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
To get a single file, import vendors.js file inside app.js file and give entry key in webpack as
entry: './src/app.js'
Let us assume that you have the files in src directory. You can merge multiple files by specifying them in webpack.config.js to have a single named file as an output. I hope this is what you are looking for.
const path = require('path');
module.exports = {
entry: {
'bundle.js': [
path.resolve(__dirname, 'src/file1.js'),
path.resolve(__dirname, 'src/file2.js')
]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [{
exclude: /node_modules/
}]
}
};
As above, the two files "file1.js" and "file2.js" will be combined into a single file "bundle.js" and stored in "dist" directory.
You can also exclude node_modules by specifying a rule in module object of webpack configuration.
I'm trying to get rid of the thousand files you get once you npm install various modules having their own dependencies.
Thus I was thinking of compiling only the libraries using webpack into one javascript file (and other required resources), then loading it to the Node.js project this way :
Entry point, that will be compiled to bundle by webpack.
module.exports = {
lodash : require('lodash'),
colors : require('colors'),
test : require('test'),
abc : require('abc')
} ;
Main
var { lodash, colors, test, abc } = require('./lib/bundle') ;
The problem I got is that some modules require system (or uncompilable) modules, such as fs, and webpack tries to bundle them to.
You just have to specify in the webpack.config.js file :
node: {
fs : "empty",
electron : "empty"
}
However, once packed into bundle, it seems that every require('fs') is replaced by Object.freeze({}) because of this setting, and then the modules fail using fs.
Would anyone have a solution for using packed modules in a Node.js project ?
P.S.: I tried using yarn with yarn autoclean --force to remove all unnecessary files, but it only removed 5% to 10% of the total.
The problem using the current node config object and set fs: 'empty' is that it will provide an empty object for those modules. More info about Webpack Node here.
You can set the Webpack target property to 'node'
Compile for usage in a Node.js-like environment (uses Node.js require to load chunks and not touch any built in modules like fs or path)
module.exports = {
target: 'node'
};
Read more about Webpack Targets
Also, to import a built-in module, use __non_webpack_require__
Generates a require function that is not parsed by webpack