Create library using Webpack - javascript

I would like to build an ES6 library using Webpack.
I generate a file using a webpack.config.json like that:
module.exports = {
entry: 'src/Main.js',
output: {
path: __dirname + '/dist',
filename: 'MyLib.min.js',
libraryTarget: 'umd'
}
};
And my Main.js:
import {Car} from './Car.js';
import {House} from './House.js';
import {Character} from './Character.js';
The problem:
When I want to instantiate something in my index.html (inside <script> after including "MyLib.min.js"), I've got an error:
Uncaught ReferenceError: Character is not defined
I don't understand what is wrong with my configuration, did I miss something?

It looks like you expect Character on the global scope. You can do that inside Main.js by simply adding window.Character = Character.

Related

Access to Button click handler not executing in a webpack project

I have a very simple setup to understand the webpack basics.
Below is my project structure
While running the project and upon clicking on the buttons in the index.html page, the handlers are not getting executed instead log errors in the console.
Please find the project here
This may be a very silly question, but I could not understand this behavior. Hope someone can help me with this. Thanks!
You can't use the functions unless you export them when you use webpack.
index.js
export function click_blue() { ... }
export function click_red() { ... }
webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
library: 'lib', // add this!
},
mode: 'development'
};
index.html
...
<button onclick="lib.click_red()">Red</button>
...
Check webpack output.library for more information.

webpack5 output.library can't import

problem
I use <script> to import index.bundle.js which bundled by webpack5 in a HTML.But I failed.
option file
//webpack.config.js
const path = require('path');
module.exports = {
entry: {
index: '/src/index.ts'
},
output: {
path: path.join(__dirname, 'dist'),
library: 'test',
libraryTarget: 'umd',
}
}
//index.ts
export function mount() {
console.log("mount")
}
//html
<script src="dist/index.js"></script>
<script>
console.log(window.mount());
</script>
error
Uncaught TypeError: window.mount is not a function
code
I have checked the official documentation.But I can't find answer.
my code is here
use
yarn
npm run build
then open the index.html,you can find the error.
Using the config you currently have (which is not putting them on the root window object), you can access your functions with window.test.mount(), because that's what you have in library in the webpack config.
If you want to put these functions on the root window object, you'd need to do that in your code:
export function mount() {
console.log("mount")
}
window.mount = mount
// etc.
You can see this by checking out dist/index.js (dropping it in the Prettier tool online can clean it up enough to be readable).

How to import a custom UMD module in a Webpack 4 project

I am developping a library that needs to work in both node and a react app. I use a webpack 4 project that generates a UMD module, but I have a problem when I try to import it in a simple webpack project.
When I use import lib from 'myLib'; lib is undefined
This is what my lib look like
export const printMsg = function() {
return "This is a message from the lib";
};
With this webpack configuration
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "mylib.js",
library: "mylib",
libraryTarget: "umd",
umdNamedDefine: true,
globalObject: `(typeof self !== 'undefined' ? self : this)`
}
};
for now I'm using a boilerplate project (https://github.com/wbkd/webpack-starter) to test.
I used npm install --save mylib to add it, and my dist code is inside my node_modules folder.
My index.js file look like this :
import "../styles/index.scss";
import lib from "watson-tile-lib";
console.log(lib);
When I run the page I got undefined in my browser console.
Any idea ?
what is your main field in package.json? It should be the builded target like:
main: "dist/mylib.js"

SyntaxError: Unexpected token export

I'm working on a npm package called foobar, locally, to allow me to make changes or modifications in real time without having to publish/unpublish to improve development time and sanity.
In projectTest, I have linked foobar by using the command npm link foobar. If you don't know, the npm link flag creates a symlink to your globals (you can read more about it here: https://docs.npmjs.com/cli/link)
The projectTest happens to be a Reactjs project, written in ES2015, Webpack, babel, etc; and where I do import { x } from 'package', without any issues, etc.
As mentioned, the package foobar exists in the node_modules has a link to its development directory, but for some reason, when I try to import:
import { myFn } from 'foobar'
The following error is thrown into the console:
/foobar/lib/index.js:3
export const loadImage = () => {
^^^^^^
SyntaxError: Unexpected token export
at Object.exports.runInThisContext (vm.js:78:16)
at Module._compile (module.js:543:28)
This is not expected, based in the fact that other imports inplace work perfectly; Why doesn't this happen in the other existing imports where the code is also ES2015? It's not transpiled ahead or to a static file, but in real time AFAIK, since I have webpack setup with babel loader like:
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var AssetsPlugin = require('assets-webpack-plugin')
var assetsPluginInstance = new AssetsPlugin()
module.exports = {
devtool: 'inline-source-map',
context: path.resolve(__dirname, 'src'),
entry: [
'react-hot-loader/patch',
'webpack/hot/dev-server',
'webpack-hot-middleware/client',
'babel-polyfill',
'./js/index.js'
],
output: {
path: __dirname,
publicPath: '/assets/',
filename: 'js/bundle.js?[hash]'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
'babel-loader'
]
}
...
}
I'd like to understand the reason of this happening! So, to help me trace the issue, tried an import that is not to the node_module's linked package, but instead, to the full or relative path, for example:
import { myFn } from '/bar/zoo/lar/deep/foobar'
Where I have placed an equivalent syntax/file, of a working import that is my utils or helper functions, that I use across the project without problems. The syntax is:
export const myFn = () => {
return 'myFn call!'
}
Where I import it from my app.js let's say, like:
import { myFn } from './utils' // works fine! BUT if I DO:
import { myFn } from '/path/to/packageFoobar' // I get the syntax error!
SO user #felixKling left a nice comment about webpack node_module being ignored, which I've now tested but I still get the error after removing the node_module:
(function (exports, require, module, __filename, __dirname) { export const styleObjectParser = str => {
^^^^^^
SyntaxError: Unexpected token export
at Object.exports.runInThisContext (vm.js:78:16)
at Module._compile (module.js:543:28)
From what I can see this far, is that, in the webpack dev configuration file, only the code under the context is transpiled in run time. But I might be wrong:
module.exports = {
devtool: 'inline-source-map',
context: path.resolve(__dirname, 'src'),
entry: [
'react-hot-loader/patch',
'webpack/hot/dev-server',
'webpack-hot-middleware/client',
'babel-polyfill',
'./js/index.js'
],
I'd like to confirm that changing the syntax works perfectly fine, so this is related with the context the babel-loader runs. Even though I don't understand why the syntax error happens, even when the node_module exclusion is removed.
module.exports = {
myFn: function () {
console.log('Syntax correct! myFn works!')
}
}
I am using webpack2, node v7.4.0
I think the problem is foobar project is not transpiled when linked with npm link, but projectTest shouldn't compile foobar project, it should just link it.
You have to transpile foobar with babel before you link it in other project.
You can add a build script in package.json of foobar project to transpile code into a /dist folder, and modify the main field of package.json in this way:
"main": "./dist/index.js"
Add npm run build in your development process, in order to have dist folder updated while developing foobar.
Now projectTest should link transpiled version of foobar.

How can I get my module exported to the browser without using Module.default notation?

How can I make webpack expose my module to the browser directly to the Module name instead of using Module.default?
Here is my app setup in a simplified manner to hopefully portray what I am hoping to achieve.
webpack.config.js
module.exports = {
entry: './src/app.js',
devtool: 'source-map',
output: {
path: './lib',
filename: 'app.js',
library: 'App',
libraryTarget: 'umd',
umdNamedDefine: true
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
}
};
.babelrc
{
"presets": ["es2015"],
"plugins": ["babel-plugin-add-module-exports"]
}
app.js
export default function main() {
console.log('The default function');
}
export function other() {
console.log('A random function');
}
Because I specified "App" as the "library" in the output, my library is available in the browser as App.
The weird thing is... in order to use the default function that was exported I have to do App.default. But to use the other exported function I can do this: App.other. I would expect that I could do App() to call the default exported function, and the other would be the same App.other().
Is this standard behavior in the browser or a UMD wrapped library with webpack? This does not seem to mimic the behavior of the lodash library. Is my configuration off in some way?
However, if you take a look at the lodash library (repo) in the browser, you can see that they acheived it.
Lodash is built using webpack. If you take a look inside of the package.json for lodash, you can see that the main file is lodash.js. If you take a look at that file, it appears to be UMD wrapped (UMD definition at the bottom of the file). Therefore, when I do things like:
import _ from 'lodash';
// or
import {clamp} from 'lodash';
everything works fine.
The other thing that works fine is referencing that exact file in an HTML file:
<script src="node_modules/lodash/lodash.js"></script>
Which allows me access to the lodash object.
console.log(_) // function
console.log(_.clamp) // function clamp(number, lower, upper) { ... }
How can I get the same behavior. Lodash's webpack config is much more complicated than I need, and am not sure what I need to reverse engineer.
add libraryExport: 'default' to the output configuration of webpack;
also you don't need babel-plugin-add-module-exports.

Categories