The problem:
We're facing an issue where any event listeners or global variables we attach to window
does not seem to be there in our production
build (but they are there in the development
build).
- Webpack config:
- Build script:
webpack --mode=production
Context:
We have a use case where our webapp renders inside a parent app. The parent app basically needs to tell us when we need to render our app. To do this, we have tried using event listeners as well as global functions.
How our app is loaded into the parent app
To render our webapp inside the parent app, the following happens:
- The parent app makes an HTTP call to
myappwebsite/asset-manifest.json
. This is like the defaultasset-manifest.json
that gets created for anycreate-react-app
webapp. - The parent app finds the path to the main
bundle.js
from this asset manifest, and then makes an HTTP call to fetch ourbundle.js
using this path (e.g.myappwebsite/bundle.js
). - They dynamically inject a
script
tag into theirhead
with itssrc
set to ourbundle.js
to load our app's bundled javascript. - They listen for the
onload
event of this newscript
element before trying to call any of our code or dispatching any events.
Attempt 1
Child app:
// index.tsx
window.addEventListener('renderApp', (event) => {
console.log('This is running!'); // This only prints in `development`
const { rootId } = event.detail;
ReactDOM.render(<App />, document.getElementById(rootId));
})
Parent app:
// index.tsx
console.log('Dispatch is running!'); // This prints in both `development` and `production`
const renderEvent = new CustomEvent('renderApp', { detail: rootId: 'root' });
// This runs in the script.onload function to wait for our app to load
window.dispatchEvent(renderEvent);
This code works in the development
build but not in the production
build. In production
, the dispatch does execute, but for some reason the event listener does not. When we tried to set some breakpoints on the minified production bundle, we noticed that the addEventListener
code is there, however it is not actually executing... This is strange because the addEventListener
is at the top level of the index.tsx
in the child app and is not conditionally added.
Attempt 2
Child app:
// index.tsx
window.renderApp = (rootId) => {
console.log('Child render is running'); // This only prints in `development`
ReactDOM.render(<App />, document.getElementById(rootId));
})
Parent app:
// index.tsx
console.log('Render is running!'); // This prints in both `development` and `production`
// This runs in the script.onload function to wait for our app to load
window.renderApp(rootId);
Same issue here, the code works in the development
build but not in the production
build. In production
, the call goes through but the global function does not seem to be on window
. I am able to verify this by printing out window
in the console.
It seems that any globals I set on window
or any event listeners I set to it get ignored in the production build. Is this by Webpack's design? Or do you think something is messed up in my config/build script that is causing this to happen?
The problem:
We're facing an issue where any event listeners or global variables we attach to window
does not seem to be there in our production
build (but they are there in the development
build).
- Webpack config: https://gist.github./saadq/9f2f800c88716d11410e63859382f47d
- Build script:
webpack --mode=production
Context:
We have a use case where our webapp renders inside a parent app. The parent app basically needs to tell us when we need to render our app. To do this, we have tried using event listeners as well as global functions.
How our app is loaded into the parent app
To render our webapp inside the parent app, the following happens:
- The parent app makes an HTTP call to
myappwebsite./asset-manifest.json
. This is like the defaultasset-manifest.json
that gets created for anycreate-react-app
webapp. - The parent app finds the path to the main
bundle.js
from this asset manifest, and then makes an HTTP call to fetch ourbundle.js
using this path (e.g.myappwebsite./bundle.js
). - They dynamically inject a
script
tag into theirhead
with itssrc
set to ourbundle.js
to load our app's bundled javascript. - They listen for the
onload
event of this newscript
element before trying to call any of our code or dispatching any events.
Attempt 1
Child app:
// index.tsx
window.addEventListener('renderApp', (event) => {
console.log('This is running!'); // This only prints in `development`
const { rootId } = event.detail;
ReactDOM.render(<App />, document.getElementById(rootId));
})
Parent app:
// index.tsx
console.log('Dispatch is running!'); // This prints in both `development` and `production`
const renderEvent = new CustomEvent('renderApp', { detail: rootId: 'root' });
// This runs in the script.onload function to wait for our app to load
window.dispatchEvent(renderEvent);
This code works in the development
build but not in the production
build. In production
, the dispatch does execute, but for some reason the event listener does not. When we tried to set some breakpoints on the minified production bundle, we noticed that the addEventListener
code is there, however it is not actually executing... This is strange because the addEventListener
is at the top level of the index.tsx
in the child app and is not conditionally added.
Attempt 2
Child app:
// index.tsx
window.renderApp = (rootId) => {
console.log('Child render is running'); // This only prints in `development`
ReactDOM.render(<App />, document.getElementById(rootId));
})
Parent app:
// index.tsx
console.log('Render is running!'); // This prints in both `development` and `production`
// This runs in the script.onload function to wait for our app to load
window.renderApp(rootId);
Same issue here, the code works in the development
build but not in the production
build. In production
, the call goes through but the global function does not seem to be on window
. I am able to verify this by printing out window
in the console.
It seems that any globals I set on window
or any event listeners I set to it get ignored in the production build. Is this by Webpack's design? Or do you think something is messed up in my config/build script that is causing this to happen?
-
> the global function does not seem to be on window < then this line should cause an error in production:
window.renderApp(rootId);
do you see console error? – glinda93 Commented Sep 12, 2021 at 7:18 -
@Saad have you checked for
cors
issue and there is no other application which register same name function to window – Chandan Commented Sep 12, 2021 at 18:48 -
@glinda93 Yeah, when I said "the global function does not seem to be on window" I meant that it is literally not on
window
and it causes an error. So it is confirmed that the function is not onwindow
. @Chandan The function does not exist at all onwindow
, there is no conflict. – Saad Commented Sep 13, 2021 at 2:30 -
renderApp
is defined in Child ponent. It maybe called in parent before definition? Somehow it works in dev but in production definition order matters... – glinda93 Commented Sep 13, 2021 at 5:33 - 1 Minimal reproducible example would be nice. – x00 Commented Sep 13, 2021 at 12:23
3 Answers
Reset to default 1The problem ended up being an issue where the output of our bundle was separated into main.js
and vendor.js
, but we were only loading the main.js
into the parent app.
Add a node entry with global: true
to your config:
node: {
global: true,
__filename: false,
__dirname: false,
},
Webpack does behave a bit strange when it es to windows object and we can site number of discussions on this matter.
According to this answer adding globalObject: 'this'
line to the output
section in webpack config file might fix the issue.
Other references https://github./webpack/webpack/issues/7112 https://github./markdalgleish/static-site-generator-webpack-plugin/issues/130