How to bundle npm packages with webpack and expose as an object? - javascript

I'm not actually sure this is possible, but what I'm trying to do is take a number of NPM packages, bundle them together using Webpack and expose them as an object where each package is a property.
For example, if I wanted react and react-dom bundled, it would then provide an object like:
{
'react': /* react code */,
'react-dom': /* react-dom code */
}
My current configuration is:
module.exports = {
entry: [ 'react', 'react-dom' ],
output: {
path: __dirname + '/public',
publicPath: 'http://localhost:8081/public/',
filename: 'bundle.js',
libraryTarget: 'umd',
}
};
This seems to somewhat work in the fact that it does return an object, but the object it returns is whatever the last entry package is, so in this case, the object contains all of react-dom's methods.
If I were to change the order of the entry array to [ 'react-dom', 'react' ], then only the react methods would be exposed.
The idea would be to export the object so I can access both package methods using their properties like react.Component or react.PureComponent
I've also tried using the expose-loader, but that yields the same results as above, unless I configured it incorrectly.
Any ideas on how to properly configure webpack to achieve this?

If I understand correctly what you want to do, you could just set up a, let's say, bundle-source.js with this structure:
exports.react = require('react');
exports['react-dom'] = require('react-dom');
exports.anyModule = require('anyModule');
Then you set that bundle-source.js as the entry point of your webpack conf:
module.exports = {
entry: [ '...path-to...bundle-source.js' ],
output: {
path: __dirname + '/public',
publicPath: 'http://localhost:8081/public/',
filename: 'bundle.js',
libraryTarget: 'umd',
}
};

Related

Webpack Externals Configuration for a Local Library

I want to setup my Webpack config (v4+) to exclude an import that is referencing a local library. In my app, I import this library like so:
/src/index.js
import foo from '../foo/foo'
console.log(foo);
/foo/foo.js
export default foo = "bar";
webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
externals: {
"foo": path.resolve(__dirname, "./foo/foo"),
}
};
However, this library is actually already referenced globally in the site where I'm deploying my application. So I do not want this library bundled with my application (I still need to import it so that I can transpile my typescript without errors and use intellisense).
I found out that I can easily exclude a library from being bundled by utilizing the externals property like so:
module.exports = {
externals: {
"jquery": "jQuery"
}
}
I've been unsuccessful at doing the same with the library that I'm importing. How would I go about doing this? I've tried the following and the library is still included in my bundle:
I have been researching documentation and can only seem to find examples related to node modules and nothing specific to my requirements.
Please let me know if you need any additional details. Thanks in advance!
In order for WebPack to treat your import as external, your import declaration must be using the same alias you defined in the WebPack extenals configuration, and NOT a relative path:
import Foo from 'foo';
WebPack:
module.exports = {
externals: {
"foo": path.resolve(__dirname, "./path/to/foo")
}
}

Can I have a common .env file for my app and its dependency?

I did something like this:
root/
node_modules/
myPackage/
index.js // uses the .env, can access process.env
app.js // uses the .env, can access process.env
.env
In app.js, the process object is a global, when I import myPackage the global object is also available in myPackeg/index.js. All good, hurray.
But, the node_modules/myPackage is not bundled, its just a couple of .js files with entry point at index.js. If myPackege is run through webpack build (minified, mangled) it somehow no longer is able to inherit the global process object from app.js. I don't understand why.
Webpack config of myPackage is nothing special, compiles to ES5, UMD. The code was mangled though, I excluded the 'process' from being mangled but it didn't help.
What am I missing?
webpack.config.js (without transplanting to ES5 with Babel)
module.exports = {
mode: 'production',
entry: './lib/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'myModule',
library: 'myModule',
libraryTarget: 'umd',
},
resolve: {
alias: {
lodash: path.resolve(__dirname, 'node_modules/lodash'),
'bn.js': path.resolve(__dirname, 'node_modules/bn.js'),
},
},
node: {
Buffer: false,
},
};

Ensure export compatibiliy with npm

I'm developing a npm module and I would like it to be importable by all kind of js client side app.
Right now I tried export default myObject and module.exports = myObject
The problem is export default seems to be available only in es6 app and module.exports doesn't work in pure javascript as module is not defined.
So I would like my module to be accessible if the client use React, Angular, Vue, pure Javascript or whatever... Also my module is just an object with a list of pure javascript functions inside. No tricky part here.
Is there a way to ensure that the module is available regardless of the technology the client will use ?
The subject is a bit old now but just in case someone get the same problem.
I got it working be using UMD as Yury suggested. After some unsuccessful tries I ended up using webpack directly. Never knew he was providing us these great tools to get UMD so simply. Here is my configuration file.
I export two configuration to build a normal and a minified version at the same time.
module.exports = [
{
entry: path.resolve(__dirname, "src/myLib.js"),
output: {
path: path.resolve(__dirname, "dist"),
filename: "myLib.js",
library: 'myLib',
libraryTarget: "umd",
umdNamedDefine: true,
},
mode: "development",
module: config.module,
resolve: config.resolve,
plugins: config.plugins,
},
{
entry: path.resolve(__dirname, "src/myLib.js"),
output: {
path: path.resolve(__dirname, "dist"),
filename: "myLib.min.js",
library: 'myLib',
libraryTarget: "umd",
umdNamedDefine: true,
},
mode: "production",
module: config.module,
resolve: config.resolve,
plugins: config.plugins,
},
];

Webpack not creating submodules in the library namespace

I'm trying to build a Webpack config allowing me to create multiple modules in a specific namespace. I have a the following config:
module.exports = {
entry: {
'one': './src/modules/one/one.module.js',
'two': './src/modules/two/two.module.js',
'three': './src/modules/three/three.module.js',
},
output: {
filename: '[name].module.js',
path: path.resolve(__dirname, 'dist'),
library: ['myModules', '[name]'],
libraryTarget: 'umd',
},
...
};
The problem is, that it creates a global namespace: myModules, but the submodules are not visible. I'm not able to create a new instance by running new window.myModules.one();. How can I fix that?
Assuming that you're using ES modules and that you have a default export for each module, you would have to access the default property.
new window.myModules.one.default();
Webpack 3 added the output.libraryExport option, which allows you to assign a specific export to the library target. Instead of having an object with the exports, you could have just the default export in place. For this you need to set output.libraryExport to 'default'.
output: {
filename: '[name].module.js',
path: path.resolve(__dirname, 'dist'),
library: ['myModules', '[name]'],
libraryTarget: 'umd',
libraryExport: 'default',
},
With that you can use it as you've wanted.
new window.myModules.one();

how to import a webpack submodule?

in my setup, I have a react component as part of an npm package called 'share-sheet'. It's managed by webpack as such:
webpack.config.js
...
output: {
path: path.join(__dirname, '/dist'),
filename: 'bundle.js'
},
entry: path.join(__dirname, 'src/index')
...
package.json
...
"main": "dist/bundle.js",
...
index.js
import FancyButton from 'components/FancyButton'
import FancyHellicopter from 'components/FancyHellicopter'
console.log(`my fancy button component: ${FancyButton}`)
module.exports = { FancyButton, FancyHellicopter }
On the other hand I have a webapp, which also uses webpack, which is setup as such:
app.js
import _ from 'lodash'
import sharesheet from 'share-sheet'
console.log(_) // outputs the lodash object correctly.
console.log(sharesheet) // outputs empty object.
console.log(sharesheet.FancyButton) // outputs undefined.
Once I run the app.js, the lines inside the share-sheet's index.js get printed correctly in the console, but once inside the app.js itself, the sharesheet is an empty object. So somehow the object exported at module.exports doesn't get returned once the share-sheet module is imported. what is wrong exactly ?
It's because webpack doesn't know the exporting strategy of 'share-sheet' package. Configuring output.libraryTarget to commonjs2 should solve the problem.
webpack.config.js
...
output: {
path: path.join(__dirname, '/dist'),
filename: 'bundle.js',
libraryTarget: 'commonjs2' // <----------
},
entry: path.join(__dirname, 'src/index')
...
You can find more informations about building library with webpack in here.

Categories

Resources