Passing a value to bundled React JS file? - javascript

I wonder if it is possible to pass an argument to a react entry point.
My entry point looks like this:
module.exports = {
entry: "./js/components/Application.js",
output: {
path: "./dist",
filename: "bundle.js"
},
// ...
}
My Application.js:
import React from 'react';
import ReactDOM from 'react-dom';
import AnotherComponent from './AnotherComponent';
ReactDOM.render(<AnotherComponent />, document.getElementById('content'));
Not I bundle my application with webpack and include this bundle in another application. This application provides a div with id "content":
<body>
<div id="content"></div>
<script src="bundle.js" />
</body>
I know that I can do something like
<script src="bundle.js" myargument="somevalue" />
but how can I get this value for passing it to the react component AnotherComponent as a property?

What about
<script id="bundle" src="bundle.js" myargument="somevalue" />
and then
const myScript = document.getElementById('bundle');
ReactDOM.render(<AnotherComponent
myArgument = {myScript.getAttribute('myargument')}
/>, document.getElementById('content')
);

In ReactJS file src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
window.MyReactApp = {
init: (selector, myData) => {
selector = selector.substring(1);
const renderComponent = (<homeComponent mydata={myData} />);
ReactDOM.render(renderComponent, document.getElementById(selector));
},
};
Now load the ReactJs App where you want to load.
<script type="text/javascript" src="bundle.min.js"></script>
<div id="load-myreactapp"></div>
<script type="text/javascript">
const myData = {};
MyReactApp.init('#load-myreactapp', myData);
</script>

Related

Bundle React library to UMD using a modern bundler

I have a Typescript react component/library
// src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import { Image, Shimmer } from 'react-shimmer';
function App() {
return (
<div>
<Image
src="https://source.unsplash.com/random/800x600"
fallback={<Shimmer width={800} height={600} />}
/>
</div>
);
}
const render = (id: string) => ReactDOM.render(<App />, document.getElementById(id));
export default render;
I want it to be compiled to UMD format, to be consumed in HTML
// index.html
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
<script type="text/javascript" src="./compiled.js">
render('app');
</script>
</body>
</html>
Preferably I want to use a modern bundler like tsup. Because webpack just scares me.
Is this possible?

Create Vanilla JS-compatible library with a Vue UI

I've got a Vue 3 project using Vite. When run in development mode, it opens a modal which makes some API calls.
main.js
import { createApp } from 'vue'
import { VTooltip } from 'floating-vue'
import store from '#/store'
import App from './App.vue'
import 'floating-vue/dist/style.css'
import './tailwind.css'
const app = createApp(App)
app.use(store)
app.directive('tooltip', VTooltip)
app.mount('#app')
App.vue
<template>
<Modal />
</template>
<script setup>
import Modal from './components/Modal.vue'
</script>
I want to make this project available as a library which can be installed with a <script> tag, or via NPM install, exposing a function which can be called to mount the modal, for example:
import myApi from '#me/myapi'
import '#me/myapi/dist/style.css'
myApi.show({ value: 'something' })
or
<link rel="stylesheet" href="https://unpkg.com/#me/myapi/dist/main.css">
<script src="https://unpkg.com/#me/myapi/dist/main.umd.js" />
myApi.show({ value: 'something' })
This call would initialise the library, mount it to the DOM and show the modal. I've found Vite has a library mode, which should support what I want.
My current thinking is to refactor main.js to export an initialiser function, and change the bundle entry to a class which calls the initializer:
main.js
// ...
export const initialize = (el, args) => {
const app = createApp(App)
app.use(store)
app.directive('tooltip', VTooltip)
app.mount(el)
return app
}
entrypoint.js
import { initialize } from './main'
class MyApi {
show(args) {
const element = document.createElement('div')
this.app = initialize(element, args)
}
}
export default new MyApi()
But I'm stuck at how you'd set the global variable for <script> integration (other than window.myApi = new MyApi()).
Is this the right way to go about this?

How do I solve object or props is not defined in ReactJS?

I am using a basic codebase in React that uses Webpack to compile ES6 and JSX to be backwards compatible.
I created a component using ES6 syntax and I want to display a props value into the component but I get an error in the console that says:
Uncaught ReferenceError: myCheese is not defined
at Module../src/index.js (index.js:8)
at webpack_require (bootstrap:18)
at startup:3
at startup:5
App.js
import React from "react";
import { hot } from "react-hot-loader";
class App extends React.Component {
render() {
return (
<div>
<p>Another paragraph</p>
<p>{this.props.msg}</p>
<p>
<strong>Cheese name: </strong> {this.props.cheese.name}
</p>
</div>
);
}
}
var myCheese = {
name: "Camembert",
smellFactor: "Extreme pong",
price: "3:50",
};
export default hot(module)(App);
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./styles.css";
// put component into html page
ReactDOM.render(
<App msg="I like cheese" cheese={myCheese} />,
document.getElementById("app")
);
webpack.config.base.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "dist"),
filename: "app.bundle.js",
},
module: {
...
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
};
Any help is greatly appreciated. Thanks.
You have myCheese in App.js rather than index.js
Try moving this block of code into index.js
var myCheese = {
name: "Camembert",
smellFactor: "Extreme pong",
price: "3:50",
};

React serverside rendering pointing to wrong bundle.js

I have a react server-side rendering application along with node & express js.
Routes.js
import React from 'react';
import { Route } from 'react-router-dom';
import Home from './Home';
import Test from './Test';
export default () => {
return (
<div>
<Route exact path="/" component={Home} />
<Route exact path="/test/:deviceId" component={Test} />
</div>
);
};
index.js
import express from 'express';
import renderer from './helpers/renderer';
const app = express();
app.use(express.static('public')));
app.get('*', (req, res) => {
console.log(req.url);
res.send(renderer(req));
});
app.listen(3090, () => {
console.log('listening at http://localhost:3090');
})
renderer.js
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import Routes from '../components/Routes';
export default req => {
const content = renderToString(
<StaticRouter location={req.path} context={{}}>
<Routes />
</StaticRouter>
);
return `
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="app">${content}</div>
<script src="bundle.js"></script>
</body>
</html>
`;
};
client.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import Routes from './Routes';
ReactDOM.hydrate(
<BrowserRouter>
<Routes />
</BrowserRouter>
, document.getElementById('app'));
Well, I am trying to pass a deviceId along with my route /test/:deviceId,
and my HTML template under renderer.js looks for bundle.js file under /test/build.js instead of /bundle.js
How do I make sure my bundle file always points to the correct location which is under public folder exposed by
app.use(express.static('public'));
if I visit, / route to Home component, it looks for bundle.js under correct folder which is the public folder.
Do let me know if you need any extra information.
Well, finally I have figured out what was changing the path of bundle.js with each out.
if my route is '/', it will look for bundle.js at http://localhost:3090/bundle.js
if the route is '/test/:deviceId', it will look for bundle.js at http://localhost:3090/test/:deviceId/bundle.js (in this scenario it will never find bundle.js)
I fixed it my modifying the html temlate under renderer.js
for the tag I changed path to bundle.js from 'bundle.js' to '/bundle.js'
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import Routes from '../components/Routes';
export default req => {
const content = renderToString(
<StaticRouter location={req.path} context={{}}>
<Routes />
</StaticRouter>
);
return `
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="app">${content}</div>
<script src="/bundle.js"></script>
</body>
</html>
`;
};
Now, it will always look for bundle.js under http://localhost:3090/bundle.js

ReactJs - Multiple Components - Error: Uncaught ReferenceError: require is not defined

I'm new to react, and I am having trouble with multiple components.
This is the error I get Uncaught ReferenceError: require is not defined
Code that I'm using.
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<script src="https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-xtf1/t39.3284-6/11057100_835863049837306_1087123501_n.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script type="text/babel" src="js/layout.js"></script>
</body>
</html>
layout.js
import React from "react";
import ReactDOM from "react-dom";
import Header from "./header";
class Layout extends React.Component {
render() {
return(
<div>
<Header/>
</div>
);
}
}
const app = document.getElementById("app");
ReactDOM.render(<Layout/>, app);
And header.js
import React from "react";
import ReactDOM from "react-dom";
export default class Header extends React.Component {
render() {
return(
<h1>Hello header</h1>
);
}
}
Babel handles only the transpilation part (i.e. converts es2015 and jsx syntax into valid ES5). But you still need to use either a bundler (webpack, browserify) or a module loader (systemjs or jspm) to load modules.
Here is an example using SystemJS. Example.
Configure systemjs loader to load libs from cdn
System.config({
transpiler: 'babel',
baseURL: '',
map: {
babel: 'https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js',
react: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js',
'react-dom': 'https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js'
}
});
// load application
System.import('script.js');
Import local files
// inside script.js
import React from "react";
import ReactDOM from "react-dom";
import Header from "./header.js"; //note extension
class Layout extends React.Component {

Categories