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!
The main limitation of using jQuery in React is that jQuery manually updates the DOM. On the other hand, React has its system for making changes to the DOM. It internally determines when a React app or component should re-render. It also figures out which parts of the UI need to be updated.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With