How can I access my javascript after webpack? - javascript

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.

Related

How to manually throw a webpack error from the code on a condition like a missing variable?

I have some code where I have placeholders. There are some variables that I don't know yet that I need to fill in when the code is pushed to production. Right now I have the following in a file called constants.js.
export const PublicAddress = process.env.PUBLIC_ADDRESS || console.error( "Public address is not yet set." );
This code works just fine and there will be an error logged to the console when PUBLIC_ADDRESS is empty.
However, if PUBLIC_ADDRESS was empty AND I forgot to hardcode another value, I'd like Webpack to throw an error when compiling instead. It's really important that I don't forget to put in a real value when I compile it for production.
Is that possible?
It's typically this kind of check that you can provide in your own webpack plugin. here is a basic implementation of a custom plugin that check if all string from an array refer to an env variable :
class EnvVarExistPlugin {
apply(compiler) {
const envsVarToCheck = ['TEST_VAR', 'TEST_VAR2'] // put your env var list here
envsVarToCheck.forEach(envVar => {
if (!!!process.env[envVar]) {
throw new Error(`Environment variable : ${envVar} is missing`);
}
});
}
};
module.exports = EnvVarExistPlugin
Then register your plugin in your webpack.config.js :
const { resolve } = require("path");
const EnvVarExistPlugin = require("./pathToYourPlugin");
require('dotenv').config({ path: './.env' }); // adapt path to your env file
module.exports = {
entry: resolve(__dirname, "src/index.js"),
mode: 'development',
output: {
path: resolve(__dirname, "dist"),
filename: "bundle.js"
},
plugins: [new EnvVarExistPlugin()]
};

when I use webpack function in undefined

I use webpack in my simple project when create bundle javascript file and I am typing in console function. function undefined how prevent to undefined function
in first js file
export default function read(){
console.log("hello webpack");
}
and in main js file
import read from './def';
read();
and in console I look this error
VM51:1 Uncaught ReferenceError: read is not defined
at <anonymous>:1:1
in webpack config file
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};

Exporting functions loads the whole file

I thought by exporting specific functions and use it will only include this function in a compiled file but it doesn't seem so ex:
file1:
export function redu1(state = null, action) {
return state;
}
export function redu2(state = null, action) {
return state;
}
file2:
import {redu1} from './file1';
What did i see in the compiled file that all the functions are included?
According to Webpack Tree Shaking, you should set property mode to production in your webpack.config.js file to remove dead code from bundle.
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
mode: 'production'
};

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

Writing embeddable Javascript plugin with React & Webpack

I want to be able to bundle my React app with Webpack such that distributed copies put onto a CDN can be sourced, called and initialised with a bunch of config relevant to a client.
After reading this and this, I'm setting up my webpack entry file as follows:
// ... React requires etc.
(() => {
this.MyApp = (config) => {
// some constructor code here
}
MyApp.prototype.init = () => {
ReactDOM.render(<MyReactApp config={MyApp.config} />, someSelector);
}
})();
The idea being that in my client, I can do something like the following:
<script src="./bundle.js" type="text/javascript"></script>
<script type="text/javascript">
MyApp.init({
some: "config"
});
</script>
And my MyApp#init function will render my React app inside some container on the client.
Am I thinking about this in the right way? Is there a simpler or more efficient way to go about this?
My error is Uncaught TypeError: Cannot set property 'MyApp' of undefined, since this inside the IIFE is undefined. I'd really like to understand both why this is happening and advice on how to fix it.
Thanks in advance!
So I kind of found a solution to this, as described here
If I change my webpack.config.js file to add the following attributes to the output object, i.e.
var config = {
// ...
output: {
// ...
library: 'MyApp',
libraryTarget: 'umd',
umdNamedDefine: true,
}
}
This specifies the file I'm bundling with webpack as a UMD module, so if I have a function in that file and export it...
export const init = (config) => {
ReactDOM.render(<MyReactApp config={config} />, someSelector);
}
I can then, in my client, do the following.
<script src="./bundle.js" type="text/javascript"></script>
<script type="text/javascript">
MyApp.init({
some: "config"
});
</script>
And my React app renders.
If anyone thinks this is a daft way of doing it, I'd love to hear it!
MORE INFORMATION ON WEBPACK CONFIG
Please bear in mind I haven't touched this code in a while. Given it's Javascript, the world has likely moved on and some practises may be outdated.
This is my React entrypoint file (src/index.js)
import 'babel-polyfill';
import React from 'react';
import { render } from 'react-dom';
import Root from './components/Root';
import configureStore from './lib/configureStore';
const store = configureStore();
export const init = (config) => {
render(
<Root store={store} config={config} />,
document.querySelector(config.selector || "")
);
}
This is my Webpack config (webpack.config.js)
var webpack = require('webpack');
var path = require('path');
var loaders = require('./webpack.loaders');
module.exports = {
entry: [
'webpack-dev-server/client?http://0.0.0.0:8080', // WebpackDevServer host and port
'webpack/hot/only-dev-server',
'./src/index.js' // Your appʼs entry point
],
devtool: process.env.WEBPACK_DEVTOOL || 'source-map',
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js',
library: 'Foo',
libraryTarget: 'umd',
umdNamedDefine: true,
},
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: loaders
},
devServer: {
contentBase: "./public",
noInfo: true, // --no-info option
hot: true,
inline: true
},
plugins: [
new webpack.NoErrorsPlugin()
]
};
As you can see, my Webpack config outputs my bundle.js which is what my front-end will ingest.
You have enclosure around your class.
MyApp needs to be exported or attached to the global window object before you can call it like that.
In your situation you are actually not calling MyApp.init() but you are calling window.MyApp.init(), but global object window does not have object MyApp attached to it.
// ... Simple attaching MyApp to the window (as a function)
window.MyApp = (config) => {
...
}
// ... Using class and export
class MyApp {
constructor(config){...}
}
export default MyApp
// or simply attach to the window
window.MyApp = MyApp
I would prefer to create class and export module using export. Then create another file just for attaching to the window. Since it is not considered best practice to attach classes to the window like that.
// Import module and attach it to the window
import MyApp from '.my-app'
window.MyApp = MyApp
You can look for advanced options of exporting modules as UMD, AMD...

Categories