Accessing a Javascript class's method from outside its scope - javascript

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>

Related

How can I build for cdn with webpack?

I created a module like this:
export default () => console.log('hello my_module~!')
The settings in the webpack.config.js file are as follows:
module.exports = {
// ...
output: {
// ...
library: 'hello',
libraryTarget: 'var'
}
}
And in the html file, the script code is:
<script src="/output_my_module.js"></script>
<script>
hello.default(); // yea~ It's work!!
</script>
But the way I want is as follows:
hello(); // I want use like this.
What should I do? I read webpack's doc but couldn't find a way. (Maybe I missed it because my English wasn't good...)
You should put libraryExport to your config.
library: 'hello',
libraryTarget: 'var',
libraryExport: 'default'

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.

Use rollup.js with jQuery adaptor in same file

I have the main function to export and the jQuery adaptor in the same file. And I would like to keep them this way.
Is there a way with rollup.js to create the bundle file compatible with AMD, CommonJS and Browsers?
Right now I have this test file:
//src/foo.js
export default function(){
function initialise() {
var TEST = {};
TEST.version = '1.0.0';
TEST.hello = function(){
console.log("hello man!!");
};
return TEST;
}
//jQuery adapter
(function($){
$.fn.demo = function(options) {
$.fn.demo.test = 'test';
};
})(jQuery);
return initialise;
};
And I tried using this rollup config:
// rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'umd',
globals: {
$: '$'
}
}
};
However I can't seem to have access to $.fn.demo:
// src/main.js
import jQuery from 'jQuery';
import pepe from './foo.js';
console.log(jQuery); //<--- undefined
console.log($); //<--- undefined
console.log("-- JS--");
console.log(pepe); //<---- working fine
console.log("-- $.fn.demo --");
console.log($.fn.demo); //<--- undefined
Note that in your main.js file pepe is a function (one which you exported from foo) and you didn't call it hence $.fn.demo is undefined. You must call pepe(); in order for you adapter to be executed.
See also how to tell Rollup that jquery is external and the jquery module ID equates to the global $ variable.

how to export function with webpack

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()

Categories