- Install Dependencies
npm init npm install --save-dev ts-node typescript tslib express @types/express
- Create
server.ts
in root folder of your app.import * as express from 'express'; import * as http from 'http'; import * as path from 'path'; import { AddressInfo } from 'net'; const app = express(); const PORT = 3000; const HOST_NAME = `localhost`; const PUBLIC_FOLDER = 'public'; app.use(`/${PUBLIC_FOLDER}`, express.static(path.resolve(PUBLIC_FOLDER))); app.all('/*', function(req: express.Request, res: express.Response) { res.sendFile('index.html', { root: path.resolve(PUBLIC_FOLDER) }) }) const server = http.createServer(app); server.listen(PORT, HOST_NAME) .on('listening', function() { const { port, address } = server.address() as AddressInfo; console.log(`Express server started on port ${port} at ${address}.`); })
- Create
public
folder - Create
public/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>TypeScript Web Component</title> </head> <body> <h1>Hello World.</h1> </body> </html>
- Create scripts in package.json
"scripts": { "serve": "ts-node -O '{ \"module\": \"commonjs\" }' server.ts" }
- Run your server
npm run serve
- Browse your application
http://localhost:3000
- Create
src
folder - Create
src/hello-world.ts
- "Hello World" Custom Elements
class HelloWorld extends HTMLElement { connectedCallback() { this.innerHTML = `<h1>Hello World.</h1>` } } customElements.define('hello-world', HelloWorld);
- Update
public/index.html
file<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>TypeScript Web Component</title> </head> <body> <hello-world></hello-world> <script src="public/bundle.js"></script> </body> </html>
-
Add build dependencies
npm install --save-dev rollup rollup-plugin-typescript2 rollup-plugin-node-resolve
-
Create
build.ts
import * as path from 'path'; import { rollup } from 'rollup'; const typescript2 = require('rollup-plugin-typescript2'); const resolve = require('rollup-plugin-node-resolve'); const ENTRY_FILE = `src/hello-world.ts`; const rollupConfig = { inputOptions: { treeshake: true, input: ENTRY_FILE, external: [], plugins: [ typescript2({ check: false, cacheRoot: path.join(path.resolve(), 'node_modules/.tmp/.rts2_cache'), useTsconfigDeclarationDir: true }), resolve() ], onwarn (warning) { if (warning.code === 'THIS_IS_UNDEFINED') { return; } console.log("Rollup warning: ", warning.message); } }, outputOptions: { sourcemap: true, exports: 'named', file: 'public/bundle.js', name: 'hello-world', format: 'es' } } function rollupBuild({ inputOptions, outputOptions }): Promise<any> { return rollup(inputOptions).then(bundle => bundle.write(outputOptions)); } rollupBuild(rollupConfig);
-
Add scripts to your package.json
"scripts": { ... "build": "ts-node -O '{ \"module\": \"commonjs\" }' build.ts" }
-
Build & Run your application
npm run build && npm run serve
-
Browse your app
http://localhost:3000
-
Expected error when running the application
- In the browser (chrome) open the DevTools (right click the browser then Inspect)
- Go to console tab of the browser
- Check the error (in red color)
bundle.js:17 Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function. at new HelloWorld (bundle.js:17) at bundle.js:24
-
Cause of the error.
This error means, that you need a polyfill for browser that do support (!) Custom Elements. That sounds a bit strange, but Custom Elements are defined for EcmaScript 2015+ (bases upon classes) and for supporting older browser, we normally compile down to EcmaScript 5 today. The output of your javascript is in es5 format.
-
How to resolve or fix?
- Install custom-elements polyfill.
npm i @webcomponents/custom-elements
- In your
server.ts
file addnode_modules
folder as one of your static foldersapp.use(`/node_modules`, express.static(path.resolve('node_modules')));
- Add polyfill as script tag in your
public/index.html
<script src="node_modules/@webcomponents/custom-elements/src/native-shim.js"></script> <script src="public/bundle.js"></script>
- Install custom-elements polyfill.
-
Run your application
npm run serve
-
Browse your app
http://localhost:3000
@n2o i updated the repo, when you execute
npm start
it will automatically watch thesrc
folder for changes and automatically build typescript code, you dont need to call thenpm run build
just manually refresh the page to see the changes
enjoy coding ^^