Importing React component from custom component library into HTML - html

I created a test react component library (React, Typescript) and am trying to use Rollup to package it up into UMD to I can import the component into an HTML page.
The sample component I created just takes a label prop and colors it orange. Something super simple so complex logic would be taken out of the equation.
React code to render the above text:
import * as React from 'react';
import * as Test from 'react-webpack-demo';
function App() {
return (
<div>
<h1>
{
React.createElement(Test.Brand, { label: 'Brand Label Text'})
}
</h1>
</div>
);
}
export default App;
The above component was packaged via Rollup into CJS format to be imported. I have also attempted to package the same content into UMD so it can be imported into HTML. The full rollup.config.js file is below:
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import typescript from '#rollup/plugin-typescript';
import external from 'rollup-plugin-peer-deps-external';
import packageJson from './package.json';
export default [
{
input: 'src/index.ts',
output: [
{
file: packageJson.main,
format: 'cjs',
sourcemap: true
},
{
file: packageJson.module,
format: 'umd',
name: 'Test',
sourcemap: true
}
],
plugins: [
resolve(),
babel({
exclude: 'node_modules/**',
presets: [
'#babel/preset-react',
'#babel/preset-typescript'
]
}),
external(),
commonjs(),
typescript({ tsconfig: './tsconfig.json' })
],
external: [
...Object.keys(packageJson.dependencies || {}),
...Object.keys(packageJson.peerDependencies || {})
]
}
]
I then attempt to import the newly packaged UMD file into my HTML page and render it into a DOM element as such:
<html lang="en-US">
<head>
<title>Test</title>
<meta charset="utf-8" />
<script src="./react-webpack-demo/dist/umd/index.js" crossorigin></script>
<script src="https://unpkg.com/react#17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.development.js" crossorigin></script>
</head>
<body>
<h1>Testing rollup in plain HTML</h1>
<hr />
<div id='brand-test'></div>
<script>
const el = React.createElement;
const domContainer = document.getElementById('brand-test');
ReactDOM.render(el(
Test.Brand,
{
label: 'Demo works!'
}
), domContainer);
</script>
</body>
</html>
But I get the following error:
The above error occurred in the component:
Brand#file:///Users/jacorbello/repos/temp/react-webpack-demo/dist/umd/index.js:33:1
Uncaught TypeError: React__namespace.createElement is not a function
Brand Brand.tsx:8
React 17
test.html:20 Brand.tsx:8:11
Any help would be greatly appreciated here.
Thanks in advance for your time!

Seems like the script tag is in incorrect order. Your library needs React to be imported before it's script can be executed.
Just fix the order to get it working
<script src="https://unpkg.com/react#17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.development.js" crossorigin></script>
<script src="./react-webpack-demo/dist/umd/index.js" crossorigin></script>

Related

How to set HTML lang attribute dynamically on NextJs Document?

I have a multi language site and need to set up the HTML lang attribute according the language for the each page.
I try to pass the value in context, but does not update when page changes.
Here the current code:
import Document, { Html, Head, Main, NextScript } from 'next/document'
import GlobalContext , {eLanguage }from '../components/GlobalContext' //my global context
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
static contextType = GlobalContext;
render() {
console.debug('Started')
console.debug('language:'+ this.context.language)
return (
<Html lang={eLanguage[this.context.language]}> //if the first page loaded as lang 'en' it sets 'en' and apply to all other pages.
<Head>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
Update:
The language of each page can be inferred from the page route
I believe the best solution here is to use a custom ./pages/_document.js file and override the document itself.
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
More explanation can be found here: https://nextjs.org/docs/advanced-features/custom-document
Next 10 supports Internationalized Routing and will add lang dynamically leaving you with:
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
If you use next/head you can set the language to the html tag. Anything that you pass to the Head component will be either placed in the <head> or <html>.
Next Head works similar to React Helmet, so for your case you could do something along these lines:
Create a component and import Head from "next/head"
Inside the Head tag you add the <html lang={lan} /> to the component.
Then you can pass the desired language to that component, then import the component on the desired pages.
import React from "react"
import Head from "next/head"
const Language = ({title, lang}) => (
<Head>
<html lang={lang} />
<title>{title}</title>
</Head>
)
export default Language
That html bit will be injected inside the <html> tag.
Note that even if we inject it like this the console will log the following error: TypeError: n is null.
I implemented this by adding this to next.config.js file:
i18n: {
// These are all the locales you want to support in
// your application
locales: ['en-US'],
// This is the default locale you want to be used when visiting
// a non-locale prefixed path e.g. `/hello`
defaultLocale: 'en-US' }
I didn't have the need to create a custom _document.js
Create _document.js in `pages`` folder
and use this:
import Document, { Head, Html, Main, NextScript } from 'next/document';
class MyDocument extends Document {
static async getInitialProps(context) {
const initialProps = await Document.getInitialProps(context);
return { ...initialProps };
}
render() {
return (
<Html lang={this.props.locale}>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
for localization use next.config.js
{
i18n: {
locales: ['en', 'fr', 'de',],
defaultLocale: 'en',
},
}
Nextjs versions after 10 provides default localization support,
You don't have to configure much.
It automatically adds lang attribute to html, but still there is no support until now with v12 for dir attribute to include that we can use this small trick inside _document file.
import { Head, Html, Main, NextScript } from "next/document";
function Document(props: any) {
return (
<Html dir={props.__NEXT_DATA__.locale === "en" ? "ltr" : "rtl"}>
<Head></Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
export default Document;
The end result would be
You can use a React useEffect hook to set the document's language without having to change the way that Next.js generates the HTML tag itself.
Within your page component or another appropriate component, include the useEffect hook:
import {useEffect} from "react";
And then add the hook:
const MyPage = () => {
useEffect(() => {
document.documentElement.lang = "en-us";
});
// The rest of your component
}
This passes Lighthouse's check for "hreflang", and if your site has multiple languages, you can use this to set the page language per page.
You can add the lang attribute without creating _document.js
All you need to do is add this code to your next.config.js:
i18n: {
locales: ['en'],
defaultLocale: 'en',
},
Using document object the lang attribute can be set like this:
var language= ...
switch (language) {
case en: document.documentElement.lang = 'en-us'; break;
...
}
This lang attribute will not be set on the initial html, before page is hydrated, but will still pass chrome "hreflang" audit check.
Most answers assume that the lang attribute is on the html tag is an alternative to link with a hreflang attribute. However, this is not the case!
You should provide both, as they are complementary.
This is how I implemented my hreflang links in NEXT.JS:
export const LayoutController = () => {
const router = useRouter();
return (
<Layout>
<Head>
{router.locales.map((locale) => (
<link
key={locale}
rel="alternate"
href={`${process.env.NEXT_PUBLIC_BASE_URL}${
locale === DEFAULT_LOCALE ? '' : `/${locale}`
}${router.asPath}`}
hrefLang={locale}
/>
))}
</Head>
{children}
</Layout>
);
};
These links were generated in my html page:
To overide default nextjs settings create the file ./pages/_document.js and extend the Document class as shown below:
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
Custom attributes are allowed as props, like lang:
<Html lang="en">
You can read more about custom document here: https://nextjs.org/docs/advanced-features/custom-document

coding reactjs with the build in of html

Im starting coding reactjs and im confusing how html5 work on reactjs. Do we need to build a separate html5 sheet or code html5 direct into jsx sheet?
React is component based java-script lib. so on your html code just link jsx by main.js code structure. your xml code build and make application in the extension of JSX like App.jsx . Refer here to build react app
index.html
This is just regular HTML. We are setting div id = "app" as a root element for our app and adding index.js script which is our bundled app file.
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>React App</title>
</head>
<body>
<div id = "app"></div>
<script src = "index.js"></script>
</body>
</html>
App.jsx
import React from 'react';
class App extends React.Component {
render() {
return (
<div>
Hello World!!!
</div>
);
}
}
export default App;
main.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx';
ReactDOM.render(<App />, document.getElementById('app'));

How to pass props from template to react root node?

I have managed to render my component on a div on my template like so:
Index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
</head>
<body>
{% load render_bundle from webpack_loader %}<h1>Example</h1>
<div id="react-app"></div>
{% render_bundle 'main' %}
</body>
</html>
My react app:
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
const rootElement = document.getElementById('react-app');
ReactDOM.render(<App />, rootElement);
Whats a good approach to pass in data to react? i'm using Django templates
It is possible to pass props to the root element through data attributes and pass them to root element in index.js
<div
id="root"
data-custom-props='{aKey: "a value"}'
></div>
index.js file:
ReactDOM.render(<App {...(root.dataset)}/>, root);
A common pattern is to output a json string into a script tag, which you can then refer to in your init function.
For example:
// Above where you include your main bundle
<script>
window.__INITIAL_STATE.__ = { your: 'DATA', encodedIn: 'json', here: true }
</script>
You can then reference window.__INITIAL_STATE__ in your index.js and pass data as props into your root component.
What data do you want to pass to react?
Props is the concept that allow user to pass data from one component to another within react. It is not made to pass data from outside world to react app.
I believe this answer can guide you in right direction.
How to get Django and ReactJS to work together?
also read following to get some idea of back-end and front-end working together.
http://geezhawk.github.io/using-react-with-django-rest-framework
http://www.openmindedinnovations.com/blogs/3-ways-to-integrate-ruby-on-rails-react-flux

Routing from express works but not from React js react-router

In my webpack, the entry point of the application is set to index.js:
entry: {
app: [
'react-hot-loader/patch',
'./client/index.js'
]
In node Js, For path / in my application, I am routing it to index.html
from routes.js on server side using:
app.route('/*')
.get((req, res) => {
res.sendFile(path.resolve(`${app.get('appPath')}/index.html`));
});
Above code understandably serves index.html.
But what if I wanted my application routing to be initialized using React-router?
index.html gets rendered but I don't see index.js getting initialized at all.It is defined as entry point in webpack so that should happen ,right?
Problem: To have React-routing initialized which should work once the flow gets to index.js
My routes.js in client folder looks like this :
import React from 'react';
import {Route, IndexRoute} from 'react-router';
import About from './components/About/About';
import Header from './components/Header/Header';
import Outlet from './components/Home/SelectOutlet';
console.log("routes file client")
export default (
<Route path="/" component={Header}>
<IndexRoute component={Outlet}/>
<Route path="about" component={Footer}/>
</Route>
);
and index.js
import 'babel-polyfill'; //certain functions like array.from , set, map can't be transpiled by babel so ue poyfill for that
import React from 'react';
import { render } from 'react-dom';
import { Router, browserHistory } from 'react-router';
import routes from './routes';
//import '../node_modules/bootstrap/dist/css/bootstrap.min.css'; //webpack can import CSS files too
import './styles/styles.css';
render((
<Router history={browserHistory} routes={routes}/>),
document.getElementById('app')
);
console.log("In index js render ")
Consoles in index.js and routes.js never get consoled and the application just serves index.html because of express routing
my webpack file is taken from here: https://github.com/Hashnode/mern-starter
but I don't see bundle.js getting created anywhere with npm start command.
Edit:
error screenshot:
screen 1:
error message
When I click on this error message:
I get all the content from html in js:
<!DOCTYPE html>
<html>
<head>
<title>
ABC
</title>
</head>
<body>
<h1> XYZ</h1>
<div id="app"></div>
<script src="index.js"></script>
</body>
</html>
Well... Are you including
<script src="index.js"></script>
in your index.html?...

AngularJS - "import" different JS files from HTML

I was trying to import certain script depending on which URL I'm.
Simple <script> tag in my HTML is:
<html ng-app="myApp">
...
<script type="text/javascript" src="{{srcRoute}}" language="JavaScript"></script>
...
</html>
I was trying to get this after main module "myApp", in a run block:
angular.module('myApp', [])
.config(function($routeProvider) {
$routeProvider.
when('/', {controller: MyController, templateUrl: 'partials/home.html'}).
otherwise({redirectTo: '/'});
})
.run(function($rootScope) {
$rootScope.srcRoute = 'some/route/here.js';
});
but when running this I get something like:
GET myRoute/%7B%7BsrcRoute%7D%7D 404 (Not Found)
What I want to do is add a conditional sentence in the run block to decide which route to use. Is there a way to do this?
Thanks!