How can I build for cdn with webpack? - javascript

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'

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

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

Calling webpacked code from outside (HTML script tag)

Suppose that I have class like this (written in typescript) and I bundle it with webpack into bundle.js.
export class EntryPoint {
static run() {
...
}
}
In my index.html I will include the bundle, but then I would also like to call that static method.
<script src="build/bundle.js"></script>
<script>
window.onload = function() {
EntryPoint.run();
}
</script>
However, the EntryPoint is undefined in this case. How would I call the bundled javascript from another script then?
Added: Webpack config file.
It seems that you want to expose the webpack bundle as a library. You can configure webpack to expose your library in the global context within a variable of your own, like EntryPoint.
I don't know TypeScript so the example uses plain JavaScript instead. But the important piece here is the webpack configuration file, and specifically the output section:
webpack.config.js
module.exports = {
entry: './index.js',
output: {
path: './lib',
filename: 'yourlib.js',
libraryTarget: 'var',
library: 'EntryPoint'
}
};
index.js
module.exports = {
run: function () {
console.log('run from library');
}
};
Then you will be able to access your library methods like you expect:
<script src="lib/yourlib.js"></script>
<script>
window.onload = function () {
EntryPoint.run();
};
</script>
Check the gist with the actual code.
I managed to get this working without any further webpack.config.js modifications, by simply using the import statement which i called from my main/index.js file:
import EntryPoint from './EntryPoint.js';
window.EntryPoint = EntryPoint;
For reference, here's my weback.config.js file.
Initially I tried accomplishing the same using require, however it assigned the module wrapper to window.EntryPoint as opposed to the actual class.
In my circumstance I was able to call a function from within the bundled JavaScript from another script by writing the function to the window when creating it.
// In the bundled script:
function foo() {
var modal = document.createElement('div');
}
// Bind to the window
window.foo = foo;
// Then, in the other script where I want to reference the bundled function I just call it as a normal function
<button onClick="window.foo()">Click Me</button>
I wasn't able to use Babel so this worked for me.
I had a similar challenge, I wanted to create a bundle for multiple pages within a journey and wanted each page to have it's own entry point into the code, and without a separate bundle for each page.
Here's my approach, which is very similar to Kurt Williams but from a slightly different angle, also without changing webpack config:
JourneyMaster.js
import { getViewData } from './modules/common';
import { VIEW_DATA_API_URL } from './modules/constants';
import { createLandingPage, createAnotherPage } from './modules/components/pageBuilder';
window.landingPageInit = () => {
getViewData(VIEW_DATA_API_URL).then(viewData => {
createLandingPage(viewData);
});
};
window.anotherPageInit = () => {
getViewData(VIEW_DATA_API_URL).then(viewData => {
createAnotherPage(viewData);
});
};
// I appreciate the above could be one liners,
// but readable at a glance is important to me
Then an example of how I call these methods at the end of the html page:
<script src="/js/JourneyMaster.js"></script>
<script>window.landingPageInit();</script>
WEBPACK.CONFIG.JS
1.USING UMD
module.exports={
mode:'development',
entry:'./yourentry.js',
output:{
path:path.resolve(__dirname,"dist"),
filename:'main.js',
publicPath:'/dist/',
libraryTarget:'umd',
library:'rstate',
umdNamedDefine: true,
libraryExport: 'default'
}
}
index.html
<script src="dist/main.js"></script>
<script>
window.onload = function () {
rstate()=>{}
</script>
main.js
export default function rstate(){
console.log("i called from html")
}
2.USING VAR
module.exports={
mode:'development',
entry:'./yourentry.js',
output:{
path:path.resolve(__dirname,"dist"),
filename:'main.js',
publicPath:'/dist/',
libraryTarget:'var',
library: 'EntryPoint'
}
}
index.html
<script>
window.onload = function () {
EntryPoint.rstate()=>{}
</script>
main.js
module.exports={
rstate=function(){
console.log("hi module")
}
}
3.USING AMD as library we use like(for those who want to make lib)
define(['jquery', './aux-lib.js'], function ($) { ..(1).. });
Many of the answers so far work, it would only be necessary to clarify that Webpack will not recognize the library until it is built once declared.
You should use npm run build right after creating your library,
before continuing to work with npm start.
At least that's how it works for me, using only webpack.
Maybe this is some impostor syndrome on my part, but I think 'real' coders will cringe at my answer. Regardless, I found this solution to be the best fitting for being pragmatic about my time with my hobby project:
Chane your JS function declaration from:
function renderValue(value) {
to:
global.renderValue = function(value) {
Of course, you'll want to require('path/to/your_custom_js') as you would any file.
I found this answer here:
https://www.fastruby.io/blog/rails/webpack/from-sprockets-to-webpacker.html
This took me forever to figure out as the accepted answer wasn't working for me. Just make sure the function name is the same as the library in the config and it's bundled with the config specified -- npx webpack --config webpack.config.js --mode=development -- hopefully this saves people a few hours.
index.js (function to be bundled) >>
function EntryPoint() {
console.log('called from bundle');
}
module.exports = EntryPoint;
webpack.config.js >>
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'var',
library: 'EntryPoint'
},
};
start.html (where the bundled function is called) >>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Azure SDK Storage Example</title>
<script type="text/javascript" src="./dist/main.js"></script>
</head>
<body>
<h1>Azure SDK Storage Example</h1>
</body>
</html>
<script>
EntryPoint();
</script>
App.ts:
namespace mytypescript.Pages {
export class Manage {
public Initialise() {
$("#btnNewActivity").click(() => {
alert("sdc'");
});
}
}
}
mypage.html:
<input class="button" type="button" id="btnNewActivity" value="Register New Activity" />
<script type="text/javascript">
var page = new mytypescript.Pages.Manage();
page.Initialise();
</script>

Categories