Create Angular and React Applications with Shared Web Components

Create Angular and React Applications Together With Nx and Smart HTML Elements

Companies usually use more than one javascript framework. Today, most popular are Angular and React. With the help of NX, we can create full-stack applications and share code between the backend and the frontend.

Creating a New Nx Workspace

We start by creating a new Nx workspace. The easiest way to do this is to use npx.

	npx --ignore-existing create-nx-workspace myApp --preset=empty
	

Creating an Angular Application

An empty workspace has no application or libraries: nothing to run and nothing to test. Let’s add an Angular application into it by running ng g app angularapp --framework=angular. The generated main.ts, will look as follows:

	import { enableProdMode } from '@angular/core';

	import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
	import { AppModule } from './app/app.module';

	import { environment } from './environments/environment';

	if (environment.production) {
	  enableProdMode();
	}

	platformBrowserDynamic()
	  .bootstrapModule(AppModule)
	  .catch(err => console.error(err));
	
And the template of the generated component will look as follows:
	<div style="text-align:center">  
	  Welcome to {{title}}!  
	  <img  
	   width="300"  
	   src="https://raw.githubusercontent.com/nrwl/nx/master/nx-logo.png"  
	  />  
	</div>

	

This is an Angular app built with Nx.

Creating a React Application

Generating a React application is just as easy.
	ng g app reactapp --framework=react and this is what we will see:
	

Where main.ts looks like this:
	import * as React from 'react';
	import * as ReactDOM from 'react-dom';

	import { App } from './app/app';

	 ReactDOM.render(<App />, document.querySelector('myApp-root'));  
	and app.tsx contains the following component:
	import * as React from 'react';
	import { Component } from 'react';

	import './app.css';

	export class App extends Component {
	  render() {
		const title = 'reactapp';
		return (
		<div>  
		 <div style={{ textAlign: 'center' }}>  
		  <h1>Welcome to {title}!</h1>  
		  <img  
		   width="300"  
		   src="https://raw.githubusercontent.com/nrwl/nx/master/nx-logo.png"  
		  />  
		 </div>  
		 <p>  
		  This is a React app built with <a href="https://nx.dev">Nx</a>.  
		 </p>  
		</div>  
		);
	  }
	}
	
Nx has first-class React support, so all the commands we use to develop Angular applications work for React as well:
  • ng serve reactapp serves the React app
  • ng build reactapp builds the React app
  • ng test reactapp tests the React app using Jest
  • ng e2e reactapp-e2e tests the React app using Cypress
TypeScript support, Jest, Cypress, source maps, watch mode — all work with

Install Smart Web Components

	Run: npm i @smarthtmlelements/smart-elements
	

Using the Smart Custom Elements in our Angular App

To use the Smart Web Components in the Angular app, let’s start with changing the output target to es2015 in tsconfig.json because Custom Elements requires ES2015 Classes.
	{
	  "extends": "../../tsconfig.json",
	  "compilerOptions": {
		"target": "es2015",
		"types": ["node", "jest"]
	  },
	  "include": ["**/*.ts"]
	}
	

Importing the Library

Next, let’s include the new library in app.module.ts.
	import { BrowserModule } from '@angular/platform-browser';
	import { NgModule, CUSTOM_ELEMENTS_SCHEMA  } from '@angular/core';
	import { AppComponent } from './app.component';
	import '@smart-elements'; // <-- the new library
	@NgModule({
	  declarations: [AppComponent],
	  imports: [BrowserModule],
	  providers: [],
	  schemas: [CUSTOM_ELEMENTS_SCHEMA],
	  bootstrap: [AppComponent]
	})
	export class AppModule {}
	

CUSTOM_ELEMENTS_SCHEMA

CUSTOM_ELEMENTS_SCHEMA tells the Angular compiler not to error when seeing non-standard element tags in components’ templates.

Using Smart ListBox Custom Element with Angular

Open app.component.html and add the Web Component to it. Smart-ListBox is part of https://www.htmlelements.com Web Components UI Toolkit.
	<div style="text-align:center">
	  <h1>Welcome to {{ title }}!</h1>
	  <img
		width="450"
		src="https://raw.githubusercontent.com/nrwl/nx/master/nx-logo.png"
	  />
	</div>
	<p>This is an Angular app built with <a href="https://nx.dev">Nx
	Updating angular.json and tsconfig.json
	Now, open angular.json and add the smart.default.css Style to
	
	"styles": 
	   [
		"apps/angularapp/src/styles.css", 
		"node_modules/@smarthtmlelements/smart-elements/source/styles/smart.default.css"
	   ]
	
Update the tsconfig.json to add the @smart-elements path which we use.
	{
	  "compileOnSave": false,
	  "compilerOptions": {
		"sourceMap": true,
		"declaration": false,
		"moduleResolution": "node",
		"emitDecoratorMetadata": true,
		"experimentalDecorators": true,
		"importHelpers": true,
		"target": "es5",
		"module": "es2015",
		"typeRoots": ["node_modules/@types"],
		"lib": ["es2017", "dom"],
		"skipLibCheck": true,
		"skipDefaultLibCheck": true,
		"baseUrl": ".",
		"paths": {
		 "@smart-elements": ["node_modules/@smarthtmlelements/smart-elements/source/smart.elements.js"],
		 "@smart-elements-css": ["node_modules/@smarthtmlelements/smart-elements/source/styles/smart.default.css"]    }
	  },
	  "exclude": ["node_modules", "tmp"]
	}
	
Run: ng serve angularapp
The result is:

Using the Smart ListBox Element in our React App

Let’s change the target to es2015 in tsconfig.json
	{
	  "extends": "../../tsconfig.json",
	  "compilerOptions": {
		"jsx": "react",
		"target": "es2015",
		"allowJs": true,
		"types": ["node", "jest"]
	  },
	  "include": ["**/*.ts", "**/*.tsx"]
	}
	

Importing Library

Next, let’s include the new library in main.tsx.
	import * as React from 'react';
	import * as ReactDOM from 'react-dom';
	import { App } from './app/app';
	import '@smart-elements';
	ReactDOM.render(, document.querySelector('myApp-root'));
	Open app.tsx and add smart-list-box to it.

	import * as React from 'react';
	import { Component } from 'react';
	import './app.css';
	import '@smart-elements-css';
	export class App extends Component {
	  render() {
		const title = 'reactapp';
	 return (  
		<div>  
		 <div style={{ textAlign: 'center' }}>  
		  <h1>Welcome to {title}!</h1>  
		  <img  
		   width="450"  
		   src="https://raw.githubusercontent.com/nrwl/nx/master/nx-logo.png"  
		  />  
		 </div>  
		 <p>  
		  This is a React app built with <a href="https://nx.dev">Nx</a>.  
		 </p>  
		 <p>  
		  🔎 **Nx is a set of Angular CLI power-ups for modern development.**  
		 </p>  
		 <h2>Quick Start & Documentation</h2>  
		 <ul>  
		  <li>  
		   <a href="https://nx.dev/getting-started/what-is-nx">  
			30-minute video showing all Nx features  
		   </a>  
		  </li>  
		  <li>  
		   <a href="https://nx.dev/tutorial/01-create-application">  
			Interactive tutorial  
		   </a>  
		  </li>  
		 </ul>  
	   <h2>Smart ListBox Web Component</h2>  
	   <smart-list-box>    
		<smart-list-item value="Bulgaria">Bulgaria</smart-list-item>   
		<smart-list-item value="United Kingdom">United Kingdom</smart-list-item>   
		<smart-list-item value="United States">United States</smart-list-item>   
	   </smart-list-box>   
		</div>  
	   );  
	  }
	}
	

Adding Intrinsic Types

With React, Instead of registering CUSTOM_ELEMENTS_SCHEMA, we use something similar, called Intrinsic Types. Create a intrinsic.d.ts file in the same folder where the main.tsx is. Then, add the following to the file:
	declare namespace JSX {
	  interface IntrinsicElements {
		[elemName: string]: any;
	  }
	}
	
Run: ng serve reactapp

The result is: