Webpack Externals Configuration for a Local Library - javascript

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")
}
}

Related

Bundling of independent or dependent js files using webpack and exposing methods to other js files or html <script> code

I have simple three files.
one add.js
function add(x,y){
return x+y
}
two sub.js
function sub(x,y){
return x-y
}
three calc.js
console.log("Add : "+add(5,1))
console.log("Sub : "+sub(5,1))
entry.js
import 'add.js'
import 'sub.js'
import 'main.js'
after webpack when i see.
it tells add method is not found.
my webpack.config
const path = require('path');
module.exports = {
mode:'development',
entry: './entry.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
};
why the methods are not exposed to main.js.
if i add window.add = add and window.sub = sub then it is exposed, with plain js why the methods are not exposed by main.js.
The purpose of asking is i am having plenty of old js files which as multiple functions and inside html code also these functions are called.
Is there any simple configuration in webpack to expose these function?

Importing webpack bundle throws module.default is not a function

I've built a package A and trying to load and use from B.
A is being transpiled with Babel and then bundled with webpack.
A index.js:
function A_moduleFunction() { // A logic }
export default A_moduleFunction
webpack.config.js
const path = require('path')
module.exports = {
entry: path.resolve(__dirname, 'transpile/index.js'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js'
}
}
On package B, I'm trying to import A and call A_moduleFunction:
import a_moduleFunction from 'A' // A is defined in package.json
a_moduleFunction()
But Then an error is thrown:
TypeError: (0 , _a_moduleFunction.default) is not a function
I used same definitions for webpack and Babel from another project of mine, which uses requires instead of imports..
What am I doing wrong ?

Webpack is erroring when I attempt to import a directory containing modules

I'm trying to create a small npm library to make interfacing with an API a little neater. My folder structure is as follows...
dist/
index.js
src/
index.js
endpoints/
endpoint1.js
package.json
webpack.config.js
Within my src/index.js file I have..
import {endpoint1} from './endpoints'
module.exports = class lib {
...
}
When I npm run build (which runs webpack --display-error-details --mode production) webpack throws a big error saying "Module not found: Error: Can't resolve './endpoints' in 'my\project\dir\src'.
My webpack.config.js file currently looks like...
const path = require('path');
module.exports = {
mode: 'production',
entry: path.join(__dirname, '/src/index.js'),
output: {
path: path.resolve('dist'),
filename: 'index.js',
libraryTarget: 'commonjs2'
},
module: {
rules: [
{
test: /.js?$/,
exclude: /(node_modules)/,
use: 'babel-loader'
}
]
},
resolve: {
modules: [
path.resolve(__dirname, 'src/endpoints')
],
extensions: ['.js']
}
};
I can see similar questions have been asked before and the resolutions listed don't seem to work for me so I thought I'd post it incase im making a rookie error. If any more info is required just say! Sorry if it's fairly wall of texty. Thanks.
The correct import would be:
import endpoint1 from 'endpoint1';
By using resolve.modules you tell Webpack to look up non relative paths in that folder. The module name is "enpoint1".
But actually you should only do this with libraries that you use across your project, for an endpoint a relative import will be appropriate:
import endpoint1 from "./endpoints/endpoint1";
import {endpoint1} from './endpoints' means this:
import from file ./endpoints/index.js something that is exported under the name enpoint1 in that file. If you import directory then it refers to index.js under that directory, not to all other files. It doesn't exist in your setup.
Names inside {} refer to named imports. This goes only for es6 modules-style imports like import {...} from. If you ommit {} then you import the default. CommonJs-style imports like const {...} = require('') work differently. CommonJs does not have named imports and exports. It just will import default from that file and then fetch a field via object destructuring.
What you export is something unnamed(i.e. default) from file ./endpoints/enpoint1.js
Something is unnamed because you use module.exports = which is CommonJS-style export. CommonJS does not support named exports. This is equevalent to export default class lib ... in es6 modules-style exports.
IF you want to import many files under directory you can consider these solutions:
1) Often single import points are created. You make a index.js file. In it you import manually every file under the directoy that you want to export. Then you export it under names. Like this:
import a from './a.js';
import b from './b.js';
import c from './c.js';
export { a, b, c };
Then it will work
2) In some rare cases in might make sence to use fs.readdir or fs.readdirSync to scan the entire directory and dynamicly require files in a loop. Use it only if you must. E.g. db migrations.

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.

Using expose-loader with webpack 2 to load a module

I have jwplayer in my lib/ folder because no node_module exists. I tried to use expose-loader in order to be able to import it. In my webpack, I have the following basic setup in order to get this to work:
const path = require('path');
module.exports = {
// ...
module: {
rules: [{
test: /\.jwplayer\.js$/,
use: {
loader: 'expose-loader',
options: 'jwplayer', // have also tried `options: { name: 'jwplayer' }`
},
}]
},
resolve: {
alias: {
jwplayer: path.join(__dirname, './lib/jwplayer-7.7.4/jwplayer.js'),
}
},
externals: {
window: 'Window',
}
};
The strange thing is, jwplayer is exposed on the window object, but it is not available as a module.
import jwplayer from 'jwplayer';
console.log(jwplayer); // Object {} (not jwplayer)
console.log(window.jwplayer); // function jwplayer() {}
Am I loading it incorrectly? How should I load in jwplayer with webpack 2?
That's not how you use the expose loader. The expose loader tells to webpack to expose something to the global context when the bundle is loaded. My understanding is that you want to use jwplayer inside the bundle itself.
You can use the script-loader, that's how I usually import scripts (analytics, for instance)
Actually you can use
externals: ['jwplayer'],
Because externals is for passing global variables inside the bundle to be able to use them as a dependency and then you can import your library as any other
import jwplayer from 'jwplayer';
webpack documentation

Categories

Resources