how to export function with webpack - javascript

I intend to bundle all my .js using webpack.
I tried with a very simple example as following.
Function to bundle in a test.js file :
function test() {
console.log('hello');
}
Webpack configuration :
module.exports = [{
{
output: {
filename: 'test.js',
path: __dirname + '/public/javascript/dist'
},
entry: [
'./public/javascript/test.js'
]
}
]
Code to test :
<html>
<head></head>
<body>
<script src="./javascript/dist/test.js"></script>
<script type="text/javascript">
window.onload = function()
{
test();
}
</body>
</html>
But I receive the following error : Uncaught ReferenceError: test is not defined.
Question : why?
[Edit] Reponse is : "export" is missing.
Thanks to that, I updated as following:
Code to export :
export function Test() {
this.t = 1;
Test.prototype.toto = function()
{
console.log('hello')
}
}
Webpack conf :
{
output: {
filename: 'test.js',
path: __dirname + '/public/javascript/dist',
library: 'test',
libraryTarget: 'window'
},
entry: [
'./public/javascript/poc/test.js'
]
}
To create the object, I have to do : var t = new test.Test();
It's a bit heavy... Is there a way to only have to make : var t = new Test(); ?

why?
Because you haven't exported anything from your entry point and, by default, webpack generates output in umd format without polluting global scope.
You first have to export your function:
export default function test() {
console.log('hello');
}
Then specify "library" and "libraryTarget" in your webpack config. Docs. For example:
output: {
filename: 'test.js',
path: __dirname + '/public/javascript/dist',
library: 'test',
libraryTarget: 'window',
libraryExport: 'default'
},
this will generate code that adds window.test = _entry_return_.default .

Since webpack 5 you're able to export to a variable instead of binding methods to the global window.
So when you are exporting your function like so:
export default function test() {
console.log('hello');
}
And configure the library type to var (libraryTarget in earlier versions of webpack 5):
output: {
filename: 'test.js',
path: __dirname + '/public/javascript/dist',
library: {
name: 'myLibrary',
type: 'var',
},
}
You can access your method like so:
myLibrary.test()

Related

Accessing a Javascript class's method from outside its scope

I'm bundling a JS class, using webpack-4, but I cannot access any of the methods and properties of it from outside its scope. I followed some of the suggestions given here but I'm still stuck. Below you'll see a simplified version of what I need to achieve. Any suggestions on how to get this to work would be greatly appreciated. Thank you!
My webpack.config:
output: {
filename: '[name].js',
path: path.resolve(__dirname, '../../assets/js'),
library: 'MyModule',
libraryTarget: 'var',
},
The class file, Main.js:
export class Main{
prop1 = 'This is Main.prop1';
static hello = ()=>{
console.log('Hello from Main');
}
static hi = function(){
console.log('Hi from Main');
}
}
Inside test.html:
<script src="./Main.js"></script>
<script>
window.onload = function(){
var mainUX = MyModule;
console.log(mainUX); // see output below**
console.log(mainUX.prop1) // outputs 'undefined'
mainUX.hello(); // Outputs Uncaught TypeError: mainUX.hello is not a function
mainUX.hi();
};
</script>
** In the console I get:
Object { Main: Getter, … }
​Main:
​__esModule: true
​Symbol(Symbol.toStringTag): "Module"
​<get Main()>: function js()​
<prototype>: Object { … }
​​__defineGetter__: function __defineGetter__()
​​__defineSetter__: function __defineSetter__()
​​__lookupGetter__: function __lookupGetter__()
​​__lookupSetter__: function __lookupSetter__()
​​__proto__:
​​constructor: function Object()
​​hasOwnProperty: function hasOwnProperty()
​​isPrototypeOf: function isPrototypeOf()
​​propertyIsEnumerable: function propertyIsEnumerable()
​​toLocaleString: function toLocaleString()
​​toString: function toString()
​​valueOf: function valueOf()
​​​length: 0
​​​name: "valueOf"
Instead of <script src="./Main.js"></script> you should just use import Main from './main.js' in your last script tag
After a whole day trying to find an answer to my issue, I came across this article. It is very thorough, easily to follow, and my issue got solved right away. Below I am attaching the code with the corrections in case someone finds it useful.
I had to change the webpack.config file, and add default to the class export.
webpack.config:
output: {
filename: '[name].js',
path: path.resolve(__dirname, '../../assets/js'),
library: '',
libraryExport: '',
libraryTarget: 'umd',
globalObject: 'this',
},
The class file, Main.js:
export default class Main{
prop1 = 'This is Main.prop1';
hello = ()=>{
console.log('Hello from inside MainUX');
}
hi = function(){
console.log('Hi from Main');
}
}
Inside test.html:
// in the head:
<script src="./Main.js"></script>
// elsewhere in the html document
<script>
const Main = window.default;
const mainUX = new Main();
console.log(Main)
mainUX.hi();
</script>

How can I access my javascript after webpack?

I have experience in Javascript and jQuery, but I am new to webpack.
I have a file called test1.js:
exports.func1 = function() {
window.alert('hello from func 1');
};
I then have index.js, which contains the following:
import test1 from "./test1"
My webpack.config.js contains:
const path = require('path');
module.exports = {
entry: './index.js',
output: {
filename: 'app.js',
path: path.resolve(__dirname, 'dist'), //folder to put the output file
},
};
I have included app.js into my webpage and that is fine, no errors in console about file cannot be found. I want to call func1() from a button click, for example, <button onclick="func1()">Test</button>.
When I do this I get "func1 is not defined" in console output. Webpack doesn't show any errors when I run it, so it must be the way I am calling the function somehow.
I must be doing something, or not doing something, really stupid. Can someone help as I seem to be going round in circles? Thanks.
It's because test1 is the exported object. func1 is a property of test1.
test1.func1() will invoke the function
You could also import it by destructuring. Try the following:
import { func1 } from './test1'
Change test1.js to:
export default () => {
window.alert('hello from func 1');
};
Then in your index.js:
export { default as test1 } from "./test1"
If you want to consume in HTML you should build a library and update your webpack like below:
const path = require('path');
module.exports = {
entry: './index.js',
output: {
filename: 'app.js',
path: path.resolve(__dirname, 'dist'), //folder to put the output file
library: 'myApp',
libraryTarget: 'umd',
},
};
Now your function is exported and should be available for usage.

HTML error using functions from bundle.js

I've created a bundle.js file using webpack to organize all my javascript code. I was expecting to use it in my html file but having troubles using the function. An error always returns when I try to call the function index.html:9 Uncaught TypeError: App.testButton is not a function at setup.
I had the impression that if I configured the webpack with the library output specified, I would be able to access the functions via the specified library name.
What am I doing wrong?
App.js
import testButton from './testButton.js';
console.log("I'm the entry point");
testButton();
testButton.js
function testButton()
{
console.log("Test Button");
};
export default testButton;
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="dist/bundle.js"></script>
<script>
function setup()
{
console.log("Initializing a webpage");
App.testButton()
}
</script>
</head>
<body onload="setup();">
</body>
</html>
webpack.config.js
const path = require('path');
module.exports = {
entry: './app.js',
mode: 'development',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'var',
library: 'App'
},
};
I found this to work for me. I needed to modify App.js to include babel so I could use ES5 which allowed me to use require to populate module.exports.
App.js
require('babel-register')({
presets: ['env']
});
module.exports = {
testButton: require('./testButton.js'),
testButton2: require('./testButton2.js')
};
testButton.js
export function testButton()
{
console.log("Test Button");
};
testButton2.js
export function testButton()
{
console.log("Test Button 2");
};
index.html
function setup()
{
App.testButton.testButton();
App.testButton2.testButton();
}
</script>
Output in Console
Test Button
test Button 2

Webpack: How to export directly to global (without .default) containing stylesheet imports?

Context
I have a webpack.config.js like this:
/* Something here */
module.exports = {
entry: {
main: './src/index.js'
},
output: {
library: 'MyClass',
libraryTarget: 'umd',
path: path.resolve(__dirname, 'lib'),
filename: `package.js`
},
...
}
My ./src/index.js looks like this:
import MyClass from 'src/myClass'
import 'src/myStyle.css'
export default MyClass
Problem
While this works fine, it exposes MyClass class to window object as:
console.log(window.MyClass)
=> Module {default: ƒ, __esModule: true, Symbol(Symbol.toStringTag): "Module"}
This way, I cannot invoke my class by using:
new MyClass();
=> TypeError: MyClass is not a constructor
I have to invoke it like:
new MyClass.default();
=> MyClass { ... }
I can solve the problem by doing something like this in my ./src/index.js:
const MyClass = require('src/myClass')
module.exports = MyClass
/* in browser */
new MyClass()
=> Good, works fine
However, this way, I cannot import my stylesheet:
const MyClass = require('src/myClass')
import 'src/myStyle.css'
module.exports = MyClass
=> TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
Edit
The following way also solves the problem, but is done without an export:
/* webpack.config.js */
module.exports = {
entry: {
main: './src/index.js'
},
output: {
/* Need to remove library related props */
// library: 'MyClass',
// libraryTarget: 'window',
path: path.resolve(__dirname, 'lib'),
filename: `package.js`
},
...
}
/* ./src/index.js */
import MyClass from 'src/myClass'
import 'src/myStyle.css'
window.MyClass = MyClass
Question
Is there a way in Webpack for me to export a module directly to global without having to invoke with .default and at the same time import a stylesheet in the entry file?
Use output.libraryExport in your webpack.config.js. (ref)
Along with output.libraryTarget set to umd, output.libraryExport tells Webpack which property to be exported as the global variable named by the output.library.
In your case, in addition to your original configuration, set output.libraryExport to default is equivalence to append the following snippet after your compiled code.
window.MyClass /*output.library*/ = module.exports.default /*output.libraryExport*/
The configuration will be as follows.
/* Something here */
module.exports = {
entry: {
main: './src/index.js'
},
output: {
library: 'MyClass',
libraryTarget: 'umd',
libraryExport: 'default', // export the default as window.MyClass
path: path.resolve(__dirname, 'lib'),
filename: `package.js`
}
}
Have a try in the console.
> window.MyClass
class {...}
If your script is only designed to run in the web browser only why not just update window explicitly:
import MyClass from 'src/myClass'
import 'src/myStyle.css'
window.MyClass = MyClass;
I think this is a lot clearer than using indirection.

How do I add prototype function of variable constructor with webpack

I have been making my own JS library and I'm trying to remake it with webpack.
In my original file, I used prototype function for variable constructor like this:
Date.prototype.fooFunc = function(e){
// return something
};
String.prototype.barFunc = function(e) {
// return something
};
var Library = function(e){
var date = new Date();
this result = date.fooFunc().barfunc();
};
and the codeline for variable constructor prototype function gets plenty long. So that I'm trying to make a seperated file for prototype funcs.
But I have no idea how to export a property of pre-defined variables in JS module system. How can I walk through it?
Solved
prototypes.js
if ( typeof Date.prototype.myFunc == undefined ) {
var foo = new Date();
return foo.something();
};
// no export
webpack.config.js
module.exports = (env, options) => {
const config = {
target: 'web',
entry: {
'my-library': [
'./src/prototypes.js',
'./src/index.js'
],
},
output: {
filename: '[name].min.js',
library: 'myLibrary',
libraryTarget: 'var',
libraryExport: 'default',
path: path.resolve(__dirname, 'dist')
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
}
return config;
}
You Don't need to export prototype methods. As soon as you add them to an Object, they are integral part of it and will be always accessible.
You have to include the file with your prototype extensions after the Object you are extending and before they are used somewhere else in your build process.
If you are extending solely javascript native objects like Date and Math, include your extensions file as the very first in your build.

Categories