Is webpack libraryTarget 'umd' supposed to work with ES6 modules? - javascript

I'm trying to distribute a node based library with webpack.
I've seen that most of js libraries around can be used both with:
commonJs syntax
const lib = require('library')
or ES6 syntax
import * as lib from "library"
I have followed this tutorial and my final webpack.config.js looks like this:
var path = require('path');
module.exports = {
entry: './index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'sepa.js',
library: 'sepajs',
libraryExport: 'default',
libraryTarget: 'umd',
umdNamedDefine: true,
globalObject: "typeof self !== 'undefined' ? self : this"
}
};
although on the browser this import statement results in an empty module:
import * as SepaJs from "./sepa.js"
Is webpack suppose to export a commonJs based library to ES6 module library?
Should I have to transcompile it with babel? Can I have one bundle file with both module solution?

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,
},
};

Webpack authoring libraries import errors with TypeError: xxx is not a constructor

I am having trouble importing a javascript package I wrote (and published to npm) into a new project.
I created an ES6 package and bundled it using webpack. Within the package I can import the library using the bundled file using a script tag,
<script src='../dist/awesome-table-dist.js'></script>
then new up the class like so:
let awesomeTable = new AwesomeTable.AwesomeTable('record');
Works like a charm! awesome-table
I pushed the package up to npm, now I want to bring it into a new project like so:
import AwesomeTable from '#iannazzi/awesome-table'
then
let awesomeTable = new AwesomeTable('record');
which is erroring:
TypeError: _iannazzi_awesome_table__WEBPACK_IMPORTED_MODULE_0___default.a is not a constructor
Now that I am importing it to a new project I have tried a variety of ways new up the class, but seem completely stuck.
I can use the package by including the script again, but obviously I want to import so I can re-package:
<script src='node_modules/#iannazzi/awesome-table/dist/awesome-table-dist.js'></script>
Here is the webpack configuration for the package:
var path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const SRC_DIR = path.resolve(__dirname,'../src');
const DIST_DIR = path.resolve(__dirname, '../dist');
module.exports = {
entry: {
app: SRC_DIR + '/table/AwesomeTable.js'
},
output: {
path: DIST_DIR,
filename: 'awesome-table-dist.js',
library: 'AwesomeTable',
// libraryTarget: 'window'
},
module: {
rules: [
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
],
},
plugins: [
new ExtractTextPlugin('style.css')
//if you want to pass in options, you can do so:
//new ExtractTextPlugin({
// filename: 'style.css'
//})
]
};
First of all, you need to expose your lib, you can do that via defining library & libraryTarget: 'umd' properties.
Second, it is not recommended to publish lib as a bundle. Think about that scenario, You lib is composed from several parts, but not all of them are mandatory. When you ship your lib a a bundle, you are forcing your users to download redundant extra code.
The best practice today is to transpile your code via Babel to be compatible es5 and commonjs as a module system.
Recently, there is a trend to ship es6 modules in a separate folder, so that whenever your users will use bundles that supports tree-shaking, they will able to use it.

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,
},
];

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

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',
}
};

Categories

Resources