webpack export JavaScript class and use in HTML - javascript

I am using webpack and trying to use a class exported in HTML.
I am getting error when I try to access the class in HTML.
Below is the example code.
// src/app.js
// I have other imports
export class MyClass {
constructor() {
}
foo() {
console.log('In Foo');
}
}
// webpack.config.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'development',
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js',
libraryTarget: 'var',
library: 'MyClass',
}
};
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<script src="./main.js"></script>
<script type="text/javascript">
const obj = new MyClass();
obj.foo();
</script>
</body>
</html>
I am getting below error:
Uncaught TypeError: MyClass is not a constructor
Also if I have multiple classes, variables and function then how can I export from JavaScript and access from HTML?

For compiling a library with Webpack:
output: {
library: { type: 'umd' }
}

Related

TypeError: is not a function when calling class method

Apologies if this is a really basic question, but I've been struggling to find an answer.
I am trying to call a method/function inside a class client side but when I try to call it, I get TypeError testFunction is not a function
The entry point is client.ts, which (to keep it simple for now) has a single export:
export * from "./Test"
Test.ts has a class and function:
export class TestClass {
public testFunction() {
// do stuff
}
}
My webpack.config.js is as follows:
var webpack = require('webpack');
var argv = require('yargs').argv;
var debug = argv.debug !== undefined;
var config = [
{
entry: {
client: [
__dirname + '/src/scripts/client.ts'
]
},
mode: debug ? 'development' : 'production',
output: {
path: __dirname + '/dist/web/scripts',
filename: '[name].js',
libraryTarget: 'umd',
library: 'webpack',
publicPath: '/scripts/'
},
externals: {},
devtool: 'source-map',
resolve: {
extensions: [".ts", ".tsx", ".js"],
alias: {}
},
target: 'web',
module: {
rules: [{
test: /\.tsx?$/,
exclude: [/lib/, /dist/],
loader: "ts-loader",
options: {
configFile: "tsconfig-client.json"
}
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file-loader',
options: {
name: 'public/fonts/[name].[ext]'
}
},
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
'sass-loader',
]
}
]
},
performance: {
maxEntrypointSize: 400000,
maxAssetSize: 400000,
assetFilter: function (assetFilename) {
return assetFilename.endsWith('.js');
}
}
}
];
module.exports = config;
I am them embedding this in the html page:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My Bookings</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/styles/main.css">
</head>
<body>
<script src="/scripts/client.js"></script>
<script type='text/javascript'>
webpack.TestClass.testFunction();
</script>
</body>
</html>
Any pointers on what I am doing wrong would be great. If I browse the generated client.js I can see the class and method, so I am at a loss!
/*!*****************************!*\
!*** ./src/scripts/Test.ts ***!
\*****************************/
/*! namespace exports */
/*! export TestClass [provided] [no usage info] [missing usage info prevents renaming] */
/*! other exports [not provided] [no usage info] */
/*! runtime requirements: __webpack_require__.r, __webpack_exports__, __webpack_require__.d, __webpack_require__.* */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "TestClass": () => /* binding */ TestClass
/* harmony export */ });
var TestClass = /** #class */ (function () {
function TestClass() {
}
TestClass.prototype.testFunction = function () {
// do stuff
};
return TestClass;
}());
The problem is that you are trying to call a non-static method directly from TestClass instead of creating a new instance of TestClass first.
You need to either call the testFunction method on a new instance of TestClass or declare the testFunction method as a static method.

How to export a function with Webpack and use it in an HTML page?

I have a file called index.js:
"use strict";
var $ = require("jquery");
window.jQuery = $;
export function foo() {
console.log('hello world');
}
And in the same directory, webpack-config.js:
module.exports = {
entry: './index.js',
output: {
filename: './dist.js'
},
mode: "development"
};
And finally I have an index.html file which loads my bundled JavaScript, and tries to use the exported function definition...
<script src="/media/js/dist/dist.js"></script>
<script type='text/javascript'>
foo();
</script>
When I run webpack, I see no output errors.
But when I load my HTML page, I see:
(index):211 Uncaught ReferenceError: foo is not defined
at (index):211
What am I doing wrong? The dist.js file is loading perfectly OK.
Add a library property to your output configuration:
module.exports = {
entry: './index.js',
output: {
filename: './dist.js',
library: 'myLibrary'
},
mode: "development"
};
Then in index.js, you should be able to call foo() like so:
myLibrary.foo();
For this to work it's important that the foo() function is being exported with export function and not export default function

How to use js library generated with webpack in a simple html page

So I created a javascript library using the following starter project https://github.com/a-tarasyuk/webpack-typescript-babel, which uses webpack, typescript and babel.
I change the webpack config to generate a library using UMD so I can use the library in the browser and server.
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = {
entry: path.resolve(__dirname, 'src'),
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'lib'),
library: 'mylib',
libraryTarget: 'umd',
globalObject: `(typeof self !== 'undefined' ? self : this)`,
umdNamedDefine: true,
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json']
},
module: {
rules: [{ test: /\.(ts|js)x?$/, loader: 'babel-loader', exclude: /node_modules/ }],
},
plugins: [
new ForkTsCheckerWebpackPlugin(),
new CleanWebpackPlugin()
]
};
Then when I build the library, I have the index.js file in the lib directory
When I drop the index.js in a simple html. how can I use the Value class in the project? I tried the following but it throws a Uncaught ReferenceError: Value is not defined
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack App</title>
</head>
<body>
<script type="text/javascript" src="index.js">
</script>
<script>
var val = new Value();
</script>
</body>
</html>
Thanks
I found a solution but I'm not sure if that is the expected behavior. When I inspected the window object the following code works
<script>
var p = new window.mylib.Value();
p.setValue(1000);
console.log(p.getValue());
</script>
So I guess webpack is adding the library to the window object when running in the browser ?
UPDATE:
I think it's because of the globalObject is set to 'this' which will mount the library to the window when in browser.

Dynamically load/import split vendor chunks/bundles via Webpack

I have a simple sample application that is structured thusly:
/dist
index.html
app.bundle.js
moduleA.bundle.js
moduleB.bundle.js
vendors~app~moduleA~moduleB.bundle.js
[...sourcemaps]
/node_modules
[...]
/src
index.js
moduleA.js
moduleB.js
package.json
webpack.config.js
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test Dependency Pulls</title>
</head>
<body>
<script type="text/javascript" src="app.bundle.js"></script>
</body>
</html>
src/index.js
import _ from 'Lodash';
import printA from './moduleA.js';
import printB from './moduleB.js';
function component() {
var element = document.createElement('div');
var btn = document.createElement('button');
element.innerHTML = _.join(['Hello', 'webpack', '4'], ' ');
btn.innerHTML = 'printA. Click me and check the console.';
btn.onclick = printA;
element.appendChild(btn);
btn = document.createelement('button');
btn.innerHTML = 'printB. Click me and check the console.';
btn.onclick = printB;
element.appendChild(btn);
return element;
}
document.body.appendChild(component());
src/moduleA.js
import printB from './moduleB.js';
export default function printA() {
console.log('AAA I get called from moduleA.js!');
}
src/moduleB.js
import _ from 'Lodash';
export default function printB() {
console.log('BBB I get called from moduleB.js!');
}
/webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: {
app: './src/index.js',
moduleA: './src/moduleA.js',
moduleB: './src/moduleB.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
optimization: {
splitChunks: {
chunks: 'all'
}
}
}
When I pull in app.bundle.js, I expect the vendor bundle to be auto-pulled as well, since it is a dependency for app.js. Currently, this is not happening - the vendor bundle is not loaded. I'm not even seeing an attempt in the network tab.
How do I tell webpack to automatically load dependencies of a bundle?
Webpack bundling/dependency management does not work exactly in that way. You need to manually add a <script> tag to the html for each bundle (entry).
However, you may want to look into using:
html-webpack-plugin:
https://www.npmjs.com/package/html-webpack-plugin
https://webpack.js.org/plugins/html-webpack-plugin
which will automatically inject the bundle references to your html.
html-webpack-template:
https://github.com/jaketrent/html-webpack-template
may also help with additional customization/features.

webpack 4 + babel 6 + ES Module and Script consumption

I'm trying to create a library that could be used using one of following method:
import MyLibrary from 'mylibrary';
const instance = new Mylibrary();
and
<script src="mylibrary.js"></script>
<script>
var instance = new MyLibrary();
</script>
To do this I have a very simple index.js which contains:
class MyLibrary {
hello() {
console.log('hello');
}
}
export default MyLibrary;
And I installed webpack / webpack-cli / babel-core / babel-cli / babel-preset-env and babel-loader via npm.
Then I created a webpack.config.js file with the following content:
const path = require('path')
module.exports = {
entry: {
MyLibrary: './src/index.js'
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].js',
library: '[name]',
libraryExport: 'default',
libraryTarget: 'umd',
umdNamedDefine: true
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
}
]
}
};
When I test it :
<script src="MyLibrary.js"></script>
<script>
var instance = new MyLibrary();
console.log(instance.hello());
</script>
Is working
import MyLibrary from './MyLibrary.js';
console.log(MyLibrary);
I get the following error: Uncaught SyntaxError: The requested module './MyLibrary.js' does not provide an export named 'default'
If I remove the rule libraryExport: 'default'from my webpack config then:
I have to call my library like this: var instance = new MyLibrary.default();
I still having the same issue Uncaught SyntaxError: The requested module './MyLibrary.js' does not provide an export named 'default'
How can I do to get this work ?

Categories

Resources