I've got a (small) React app (vanilla create-react-app), that I would like to appear in a modal (bootstrap or similar) on another site. Is there a library that will simplify this process?
Specifically, the entire use case is that if my Javascript file is loaded (and just one javascript file), it will insert a "Click Me" type call to action, and when clicked my App component will be loaded into a new modal. It will need the CSS (for the app) to be included in some form as well.
I think all of this (excluding the call-to-action which is fairly simple) could be done during Babel/Webpack transpilation but I can't find anything off-the-shelf that seems to do this.
This functionality is built into ReactDOM.render. Simply add an id to your element.
For example:
<!-- index.html -->
<script src="url/to/react/build/asset" as="script" />
<div id="button-and-modal"></div>
Then to render your react app inside the div:
// index.js
import { render } from 'react-dom';
import App from './App'
function renderReact() {
const element = document.getElementById('button-and-modal');
render(<App/>, element)
}
document.addEventListener('DOMContentLoaded', renderReact);
Then your react app would look something like this:
const App = () => (
<div>
<Button/>
<Modal/>
</div>
)
You can also code the button and modal outside of the react app and only have the modal content rendered by react. If you want to do that, then follow the same directions but add the javascript for the button+modal inside the renderReact function.
You can use for example https://direflow.io/ to build your react app as a web component that you can render anywhere on any site.
Using your current project you can do
direflow create
cd <project-name>
npm install
and then
copy your whole app in folder into direflow-components so your project tree would look like:
/public
/src
/direflow-components
/<project-name>
// leave here only index.ts from example and copy all your project files here
index.ts
component-exports.ts
index.ts
react-app-env.d.ts
.eslintrc
...
If needed you can change
...
component: App,
configuration: {
tagname: 'example-component',
},
...
to your component that you want to render and tagname by which app will be accessible.
After all that you just do
npm run build
copy direflowBundle.js from build folder to your website
and render your app on some website like so:
<body>
<script src="./direflowBundle.js"></script>
<awesome-component></awesome-component>
</body>
I feel like I deal with this issue at every Front End job. It's definitely not easy, but I've found a number of ways to do it. I've tried the bundling idea you suggested but that one gave me the hardest time. The easiest way imo without a lot of hassle is to host your react app on a blank web page, then load it into an iframe where you need it.
At my last job, we wanted to migrate our shopify website to react, but with the way the shopify architecture was set up at the time, it made it difficult to us host a server-side rendered react app. So we built the web pages using Next.js and then deployed it to Vercel. We then inserted this as an iframe into the shopify website. It worked beautifully.
Related
I want to build a SPA on the client site, which supports a plugin concept.
You should be able to copy a package inside a specific folder and the server should load this component after a restart. This plugin should work without any information stored inside the base program.
I need to dynamically load a component by name. I do not have a map of all possible components. How can I load a component by only knowing its name?
you can check out React.lazy. This helps with dynamic loading components which you want, but with this you need to wrap it to Suspense, because component will load not immediately.
// This component is loaded dynamically
const SomeComponent = React.lazy(() => import('./SomeComponent'));
<Suspense fallback={<Spinner/>}><SomeComponent/></Suspense>
So I have a users.js JSX file with some exported component:
... return <MainContainer keywords="users"> export default Users
when using SSR/SSG, I get the users HTML (just a bunch of <li> tags) in the browser as expected
the browser also receives a .next/static/chunks/pages/users.js with digested/lower-level representation of that React component as client-side js. This gets imported via <script> in HTML.
AssumptionL that js file is for rendering, CSR-style, of the users dataset, into HTML.
Because it contains stuff like
_components_MainContainer__WEBPACK_IMPORTED_MODULE_3 ... react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_0__["jsxDEV"])("li", ....
So, clearly the js in <script> can create <li> elements as well as the server. I think it can create the whole page content, if executed.
Question: why the apparent duplication of effort? Does the browser, with SSR/G, get BOTH HTML and js and js ALSO runs producing HTML - surely not? I am using getStaticProps in my users.js
If the assumption why we have a compiled/digested React js (under .next/static) in the browser, is incorrect, then why does NextJS need this file pulled in via <script> ?
Next.js is used for server-side rendering of the react apps. React with another framework like angular and vue.js are client-side frameworks, they run in browsers but there are some technologies to run this framework on the server-side, and next.js is a solution for running react application server-side. It also makes react development very simple features of Next.js are:
Server rendering React Apps.
Automatic code splitting and lazy loading.
Built-in CSS support.
Hot Reloading support.
Let's assume we have a website, that should show a reactjs application.
The following points are necessary:
The ReactJS application should be embedded by using a short snippet (script / html)
The ReactJS app should be updated without changing the snippet itself
The ReactJS app is hosted on a completely different server
It should not be an iFrame if possible
So what I want to achieve is similary to a Google Map for instance. You have a small snippet and you can show an application on your side.
What are the best practices to do so ? What do I have to take into consideration ?
"Micro frontends":
https://medium.com/#tomsoderlund/micro-frontends-a-microservice-approach-to-front-end-web-development-f325ebdadc16
I came across this idea only recently. So, I don't have much to tell you regarding your requirements. But it looks promising. But also may be an overkill.
And by following links you'll be able to find some code examples.
E.g. https://single-spa.js.org/docs/examples/
simple example without iframe
<script>
(function(window,document, id, scriptUrl, appId){
// create container where to render app
var containerDiv = document.createElement("DIV");
containerDiv.id=appId
document.getElementById(id).appendChild(node);
// add script tag
var scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = scriptUrl;
document.body.appendChild(scriptTag);
// also you may need to send you app info about where should render (id)
window.MY_WIDGET_ID = appId
})(window,document, 'where-to-render-app-id', 'script-url', 'app-id');</script>
<script >
// inside your react app you should add
render( document.getElementById(window.MY_WIDGET_ID ))
A regular React application is a set of JS(let's ignore the CSS, images, other assets this time) files. And there is a file called the entry which mounts the entire application to a specific dom. You might be familiar with the below code.
ReactDOM.render(<App/>, document.getElementById('app'))
The above code is auto executed usually once the entry is loaded onto a predefined dom. We can expose it as an initial handler of the application.
window.apps = {} // This better be executed in a script hosted by the website
window.apps['my-app'] = dom => ReactDOM.render(<App/>, dom)
The script hosted by the website then is able to start the application by calling the function above.
window.apps['my-app'](document.getElementById('root'))
In this way, the website takes the control of initial a React application, at any time, onto any dom, or even any instance.
ps. Ignore type checks, null checks. You should add it as you need to make sure no runtime error happens.
As an other option, you could wrap your react app into web component. Here's the example. But it could be overengineering, from case to case, mpc's approach could be more reasonable easily.
you can create a shell app that will load your remote code and run it.
btw, check out fronty, it is a micro-frontend tool that can help you with that with no hassle.
This is one of the feature React offers. If you take the Basic files provided by React it is an HTML page with a <div id="root"></div>. By default, React is built as a single page App. In fact, you can edit directly this HTML file (located in Public folder) and the React will still run.
So to achieve what you are looking for, build your React project include it to your HTML project (The same include present in the public/index.html -> <script src="/static/js/main.******.chunk.js"></script>.
In the React project, you add the same render condition:
if (document.getElementById("root")) {
ReactDOM.render(
<App />
document.getElementById("root")
);
}
Wrapping the ReactDom.render in an if is to make sure the desired ID is present in your dom.
That's it, it should be working.
Have fun.
I have a vuejs project with various pages:
study.vue
result.vue
My client want me to add in the Google Tag Manager code so that they can use google analytic to track. Where should I add the code in my .vue file? Or should I just add it in the index.html?
Update01
This is what I do so far:
I add the Google Tag Manager code to the index.html.
I installed vue-gtm.
I have app.js and bootstrap.js. basically, bootstrap.js will have all my other js frameworks added. Like lodash.js or 'jquery.js'. I add the sample code from vue-gtm into bootstrap.js:
window._ = require('lodash');
window.moment = require('moment');
window.Vue = require('vue');
import VueRouter from 'vue-router';
Vue.use(VueRouter)
import VueGtm from 'vue-gtm';
Vue.use(VueGtm, {
debug: true
})
In all the vue file, I add this code:
this.$ua.trackView('Sample', 'samplepath');
However I got error:
TypeError: Cannot read property 'trackView' of undefined
What seems to be the error?
I assume you are talking about the script that you get when you create an account?
There should be two scripts to include in your HTML, one that has comments around it that include (noscript) and one that doesn't. Both should probably go in your index.html file (whichever file has the <head> and <body> tags). The one that has the noscript should go immediately after the <body> tag, the one that doesn't have the noscript should go near the top of the <head> section.
If you are asking how to fire an event, such as when the user interacts with one of those Vue elements, then yes the code for firing the event should go in the Vue component.
UPDATE 1: I looked into it and setup my own Laravel installation to test (since that seems to be what you're using) and tested it. The problem is that $ua is part of the Vue Analytics, so if you want to use $ua you need to install the vue-ua module as well and add that to Vue. I don't know why the documentation for the Tag Manager module shows how to use the Analytics module without making reference to it, maybe you should file an issue on the Tag Manager GitHub to make the documentation more clear!
So in summary, you should replace $ua with $gtm instead. I tested it and $gtm has a trackView function so it will probably achieve what you want, but I don't know how to use Google Tag Manager so you'll have to test it out yourself.
Based on the comments on another of my questions (gradle how to add files javascript fies to a directory in the war file) I'm trying to use angular-cli to help build and manage an angular project. However, I cannot seem to find any documentation on how to create a second webpage in the project, which to me seems like a very basic task. I tried creating a "component" with ng g component {component name}, but this didn't add anything to the build result.
I had missed the section of the angular docs on routing since I did not make the connection between the word "routing" and what I wanted to do. Routing as described here works perfectly when using Node as your server. However, other web servers such as Tomcat (which I am using for this project) will not since ng build only generates an index.html file. Node knows that it should re-route URLs under the angular base to that file, but Tomcat doesn't. A proxy server such as apache needs to be placed in front of the Tomcat server to redirect the urls to the base url for the application.
With that out of the way, here is the basics of routing:
create a component for each "page" (the component does not need to be responsible for the whole page displayed. see 2)
create a "shell" component that contains features that will be on all pages e.g. toolbar, side navigation.
add <router-outlet></router-outlet> to the point in the shell component component where components for sub-URLs will appear (note that they are inserted into the DOM after this tag, not within it.)
in the imports for your module, add RouterModule.forRoot(). This function takes an array of Route. Each route has a path and a component property. path is the url (relative to the base url) that will cause component to be inserted into the DOM. Note that path values should not begin with a slash.
add a tags with the routerLink property bound to the url of your new page. Note that here, there should be a leading slash.