1. Introduction
-
solidjs
-
typescript
-
plain javascript
-
es next using babel
-
rx
-
vue
-
react
-
preact
-
angularjs
-
yaml
-
markdown
-
bootstrap
-
react-hooks
-
preact-hooks
-
and many more!
other repos with old examples:
links:
generated by generator-jvm yeoman generator (java)
2. Implementation
2.1. basic example
prepare project
mkdir -p basic
echo "node_modules" >> basic/.gitignore
echo "dist" >> basic/.gitignore
echo ".cache" >> basic/.gitignore
echo '{"scripts":{"start":"parcel src/","build":"parcel build src/index.html"}}' > basic/package.json
cd basic/
npm init -y
npm i -D parcel-bundler
prepare project files
mkdir -p src
touch src/index.html
touch src/styles.css
touch src/main.tsx
main.tsx
(function main() {
'use strict';
document.addEventListener('DOMContentLoaded', function onDOMContentLoaded() {
document.querySelector('#app').innerHTML = '<h1>Hey! 📦 🚀</h1>';
}, false);
})();
styles.css
html,
body {
height: 100%;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial,
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
}
#app {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
h1 {
font-weight: 300;
}
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>Basic | Parcel</title>
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div id="app"></div>
<script src="./main.js"></script>
</body>
</html>
start development
npm start
open localhost:1234/
build bundle
npm run build
verify result
npm i -g serve
serve dist/
open localhost:5000/
2.2. babel stage-0
parcel needed only .babelrc file and installed required presets
add
.babelrc
file, install and configure presets: env
and stage-0
cp -Rf basic babel-stage-0
cd babel-stage-0/
echo '{"presets":["env","stage-0"]}' > .babelrc
npm i -D babel-preset-env babel-preset-stage-0
now you can use some cool JS features:
const obj = { ololo: 'trololo' };
document.querySelector('#app').textContent = JSON.stringify({
...obj,
hey: 'ho!',
});
done.
2.3. react
for React you need even less: just install react library and parcel will recognize everything for you!
cp -Rf babel-stage-0 react
cd react/
npm i -S react react-dom
npm i -D babel-preset-react
echo '{"presets":["env","react"]}' > .babelrc
add react component:
import React, { Component } from 'react';
export class EchoEhlo extends Component {
constructor() {
super();
this.state = {
message: 'Hey!',
};
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({
message: this.state.message.split('').reverse().join(''),
})
}
render() {
return <h1 onClick={this.toggle}>
{this.state.message} 📦 🚀
</h1>
}
}
and update code in
src/main.tsx
file:import React from 'react';
import { render } from 'react-dom';
import { EchoEhlo } from './components/echo-ehlo';
render(
<EchoEhlo/>,
document.querySelector('#app')
);
build, run, verify…
done.
2.4. preact
do necessary updates from react example:
cp -Rf react preact
cd preact/
npm rm react react-dom babel-preset-react
npm i -S preact preact-compat
npm i -D babel-preset-preact babel-plugin-transform-class-properties
echo '{"presets":["env","preact"],"plugins":["transform-class-properties"]}' > .babelrc
implement preact component:
import { h, Component } from 'preact';
export /* don't works without default O.o */ default class EchoEhlo extends Component {
state = { message: 'Hey!' };
toggle = () => {
const curr = this.state.message;
const reverced = curr.split('').reverse().join('');
this.setState({ message: reverced, });
};
render({}, { message }, {}) {
return <h1 onClick={this.toggle}>
{message} 📦 🚀
</h1>
}
}
update entry point:
import { h, render } from 'preact';
import HeloEhlo from './components/echo-ehlo';
render(
<HeloEhlo/>,
document.querySelector('#app')
);
done.
2.5. vue
to be able build vue apps, in addition to babel example you only need install vue and two dev packages:
cp -Rf babel-stage-0 vue
cd vue/
npm i -S vue
npm i -D babel-preset-vue @vue/component-compiler-utils vue-template-compiler
echo '{"presets":["env","vue"]}' > .babelrc
add vue component file:
AppUseState.vue
<template lang="html">
<div id="app">
<h1>Hey! 📦 🚀</h1>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
<style lang="css">
html,
body {
height: 100%;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial,
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
}
#app {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
h1 {
font-weight: 300;
}
</style>
main.tsx
import Vue from 'vue'
import App from './components/App.vue'
new Vue({
el: '#app',
render: h => h(App)
});
2.6. yaml
to be able to parse YAML we need js-yaml package:
cp -Rf basic yaml
cd yaml/
npm i -ES js-yaml
add YAML file:
app:
map:
key: value
list:
- value 1
- value 2
main.tsx
import app from './app.yaml';
document.addEventListener('DOMContentLoaded', function onDOMContentLoaded() {
document.querySelector('#app').innerHTML = `
<h1>Hey! 📦 🚀</h1>
<pre>${JSON.stringify(app, null, 2)}</pre>
`;
}, false);
2.7. markdown
to be able to parse YAML we need parcel-plugin-markdown package:
cp -Rf basic markdown
cd markdown/
npm i -ED parcel-plugin-markdown
add
app.md
file:# app
## ololo
**ololo article**
list:
- one
- two
- three
## trolololololo
_O_
|
/ \\
## js
<!--
---
title: JavaSCript Article'
metadata:
ololo: trololo
---
-->
### JS article
js, ololo, trololo, javascript, olololo ololo, trololo, olololo ololo, trololo, olololo ololo,
trololo, olololo, js, ololo, trololo, olololo, js ololo, trololo, olololo.....
```javascript
function ololo(arg) {
arg = arg || 'trololo';
console.log('ololo', arg);
}
```
main.tsx
import app from'./app.md';
document.addEventListener('DOMContentLoaded', function onDOMContentLoaded() {
document.querySelector('#app').innerHTML = `
<h1>Hey! 📦 🚀</h1>
<div>${app}</div>
`;
}, false);
See also markdowns and markdowns2 projects for non single md-file parsing use case…
|
2.8. markdowns (2)
example how we can handle lazy loading with parcel for markdown files lazy processing on runtime
add
./src/posts
folder with some posts in markdown format:tree markdowns2/src/posts/
markdowns2/src/posts/
└── 2018
└── 06
├── 29
│ ├── 01-ololo.md
│ └── 02-trololo.md
└── 30
├── 01-javascript.md
└── 02-bash.md
main.tsx
implementation:import marked from 'marked';
const years = require('./posts/**/*.md');
Object.keys(years).map(year => {
const months = years[year];
Object.keys(months).map(month => {
const days = months[month];
Object.keys(days).map(day => {
const posts = days[day];
Object.keys(posts)
.map(src => posts[src])
.forEach(uri => fetch(uri)
.then(resp => resp.text())
.then(markdown => marked(markdown))
.then(html => document.querySelector('#app').innerHTML += html));
});
});
});
2.9. angularjs
with no comments - I tired….
./src/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>AngularJS | Parcel</title>
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
</head>
<body>
<app> loading...</app>
<script src="./main.js"></script>
</body>
</html>
Main application bootstrap entrypoint:
./src/main.tsx
import 'angular/angular-csp.css';
import './styles.css';
//
import angular from 'angular';
import applicationModule from './app';
angular.bootstrap(document, [applicationModule.name], {
strictDi: true, // data-ng-strict-di=""
cloak: true, // data-ng-cloak=""
});
Application module config:
./src/app/index.js
/**
* Application module configuration.
*/
import angular from 'angular';
import uiRouter from 'angular-ui-router';
//
import ComponentsModule from './components';
const applicationModule = angular.module('application.module', [
uiRouter,
ComponentsModule.name,
]);
const Config = ($urlRouterProvider, $locationProvider) => {
$urlRouterProvider.otherwise('/');
$locationProvider.hashPrefix('!');
};
applicationModule.config(['$urlRouterProvider', '$locationProvider', Config]);
export default applicationModule;
Components module config:
./src/app/components/index.js
/**
* Components module configuration.
*/
import angular from 'angular';
//
import AppComponentModule from './app';
const componentsModule = angular
.module('components.module', [
AppComponentModule.name,
]);
export default componentsModule;
AppUseState module config:
./src/app/components/app/index.js
/**
* App component module configuration.
*/
import angular from 'angular';
import uiRouter from 'angular-ui-router';
//
import Config from './config.js';
import Component from './component.js';
const appComponentModule = angular
.module('app.component.module', [uiRouter])
.component('app', Component)
.config(['$stateProvider', Config]);
export default appComponentModule;
AppUseState component config:
./src/app/components/app/config.js
export default ($stateProvider) => $stateProvider.state({
url: '/',
name: 'app',
template: `<app></app>`,
});
AppUseState component:
./src/app/components/app/component.js
import Controller from './controller.js';
export default {
controller: Controller,
template: `
<header ng-click="$ctrl.toggleGreeting()">header</header>
<div class="container-fluid">
<div class="row">{{ $ctrl.greeting }}</div>
</div>
<footer>footer</footer>
`,
}
AppUseState component controller:
./src/app/components/app/controller.js
export default class Controller {
constructor() {
this.$ctrl = this;
}
$onInit() {
this.greeting = this.first = 'hi';
this.second = 'yay!';
}
toggleGreeting() {
this.greeting = this.greeting === this.first
? this.second
: this.first;
}
}
2.10. react + bootstrap (4)
prepare
cp -Rf react react-bootstrap
cd react-bootstrap/
npm i -S bootstrap
npm i -ED babel-preset-env babel-preset-react babel-preset-stage-0
file
.babelrc
{
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "safari >= 7"]
}
}],
"react",
"stage-0"
]
}
add bootstrap import and add some bootstrap class for styling:
import 'bootstrap/dist/css/bootstrap.css';
import React, { Component } from 'react';
export class EchoEhlo extends Component {
constructor() {
super();
this.state = {
message: 'Hey!',
};
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({
message: this.state.message.split('').reverse().join(''),
})
}
render() {
return <h1 onClick={this.toggle} className='alert-heading'>
{this.state.message} 📦 🚀
</h1>
}
}
done.
2.11. typescript
you don’t needed anything special. parcel compiling typescript working out of the box
document.addEventListener('DOMContentLoaded', (e: Event) => {
const app: HTMLDivElement = document.querySelector('#app');
app.innerHTML = `
<h1>Hey! 📦 🚀</h1>
`;
console.log(`event ${e.type} handled`);
}, false);
done.
2.12. rx.js + typescript
cp -Rf ts rxts
cd rxts/
npm i -E rxjs
file
main.tsx
:import { fromEvent } from 'rxjs';
fromEvent(document, 'DOMContentLoaded').subscribe((e: Event) => {
const button: HTMLButtonElement = document.querySelector('#greet');
fromEvent(button, 'click').subscribe((e: Event) => {
document.querySelector('#message').innerHTML = `
<h1>Hey! 📦 🚀</h1>
`;
});
});
done.
2.13. bootstrap.scss
cp -Rf react-bootstrap sass-bootstrap
cd sass-bootstrap/
npm i
echo '$primary: #c63 !default;' > src/_variables.scss
mv src/styles.css src/styles.scss
# similary fix index.html: styles.css -> styles.scss
remove import from file
src/components/echo-ehlo.js
:// import 'bootstrap/dist/css/bootstrap.css';
update file
styles.scss
:@import "./variables.scss";
@import "../node_modules/bootstrap/scss/bootstrap.scss";
done.
2.14. react-hooks
edit file
main.tsx
:import 'babel-polyfill';
import { render } from 'react-dom';
import React, { useState } from 'react';
function App() {
const [message, setMessage] = useState('Hello');
const reversed = str => str.split('').reverse().join('');
const toggleReverse = () => setMessage(reversed(message));
return <h1 onClick={toggleReverse}>
{ message } 📦 🚀
</h1>
}
render(
<App/>,
document.querySelector('#app')
);
done.
2.15. preact-hooks
edit file
app.js
:import { h, render } from 'preact';
import { useState } from 'preact/hooks';
import React from 'preact/compat';
function App() {
const [message, setMessage] = useState('Hello');
const reversed = str => str.split('').reverse().join('');
const toggleReverse = () => setMessage(reversed(message));
return <h1 onClick={toggleReverse}>
{ message } 📦 🚀
</h1>
}
render(
<App/>,
document.querySelector('#app')
);
done.
2.16. react-hooks-typescript
install packages
npm i -ED parcel-bundler parcel-plugin-static-files-copy scss
npm i -ED typescript @types/node @types/react @types/react-dom
npm i -ED babel-core babel-preset-env babel-preset-react @babel/preset-typescript
npm i -E react react-dom
key
package.json
features:{
"name": "react-hooks-ts-app",
"main": "./src/index.html",
"devDependencies": {
"@babel/preset-typescript": "7.9.0",
"@types/node": "13.9.2",
"@types/react": "16.9.25",
"@types/react-dom": "16.9.5",
"babel-core": "6.26.3",
"babel-preset-env": "1.7.0",
"babel-preset-react": "6.24.1",
"parcel-bundler": "1.12.4",
"parcel-plugin-static-files-copy": "2.3.1",
"pm2": "4.2.3",
"sass": "1.26.3",
"typescript": "3.8.3"
},
"dependencies": {
"react": "16.13.1",
"react-dom": "16.13.1"
},
"staticFiles": {
"staticPath": "./src/public",
"watcherGlob": "**"
},
"babel": {
"presets": [
"env",
"react"
]
},
"scripts": {
"dev": "parcel src/index.html --no-cache",
"build": "parcel build src/index.html --no-cache",
"start": "pm2 start 'npm run dev' --name app",
"restart": "pm2 restart app",
"stop": "pm2 kill",
"logs": "pm2 logs"
}
}
edit file
main.tsx
:import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { App } from './components/App';
import { StoreProvider } from './store/Store';
import { UseStateApp } from './components/UseStateApp';
import { UseReducerApp } from './components/UseReducerApp';
import { UseContextStoreApp } from './components/UseContextStoreApp';
const { render } = ReactDOM;
render(
<React.Fragment>
<p>app:</p>
<App/>
<br/>
<p>useState app:</p>
<UseStateApp/>
<br/>
<p>Provider useContext app:</p>
<StoreProvider>
<UseContextStoreApp/>
</StoreProvider>
<br/>
<p>useReducer app:</p>
<UseReducerApp />
<br/>
</React.Fragment>,
document.querySelector('#app')
);
edit file
components/App.tsx
:import * as React from 'react';
export const App = () => <h1>
React Hooks TypeScript Apps 📦 ⚛️ 🚀
</h1>
edit file
components/UseStateApp.tsx
:import * as React from 'react';
const { useState } = React;
export function UseStateApp(): JSX.Element {
const [state, setState] = useState<string>('Store');
const reverse = () => setState(state.split('').reverse().join(''));
return (
<h1 onClick={reverse}>
state: { state } 📦 ⚛️ 🚀
</h1>
);
}
edit file
components/UseReducerApp.tsx
:import * as React from 'react';
import { reducer } from '../store/Store';
const { Fragment, useReducer } = React;
export function UseReducerApp(): JSX.Element {
const [state, dispatch] = useReducer(reducer, { message: 'reducer app' });
return <Fragment>
{console.log('reducer:', state)}
<h1 onClick={() => {
dispatch({ type: 'SET', payload: state.message });
}}>
{ state.message } 📦 ⚛️ 🚀
</h1>
</Fragment>
}
edit file
components/UseContextStoreApp.tsx
:import * as React from 'react';
import { Store, reducer } from '../store/Store';
const { Fragment, useContext, useReducer } = React;
export function UseContextStoreApp(): JSX.Element {
const store = useContext(Store); // see main.tsx => StoreProvider
const [state, dispatch] = useReducer(reducer, store);
return <Fragment>
{console.log('store:', store, 'state:', state)}
<h1 onClick={() => {
dispatch({ type: 'SET', payload: state.message });
}}>
{ store.message } 📦 ⚛️ 🚀 { state.message }
</h1>
</Fragment>
}
done.
2.17. preact-hooks-typescript
install packages
npm i -ED parcel-bundler parcel-plugin-static-files-copy scss
npm i -ED typescript @types/node
npm i -ED babel-core babel-preset-env babel-preset-preact @babel/preset-typescript
npm i -E preact
key
package.json
features:{
"name": "react-hooks-ts-app",
"main": "./src/index.html",
"devDependencies": {
"@babel/preset-typescript": "7.9.0",
"@types/node": "13.9.2",
"@types/react": "16.9.25",
"@types/react-dom": "16.9.5",
"babel-core": "6.26.3",
"babel-preset-env": "1.7.0",
"babel-preset-react": "6.24.1",
"parcel-bundler": "1.12.4",
"parcel-plugin-static-files-copy": "2.3.1",
"pm2": "4.2.3",
"sass": "1.26.3",
"typescript": "3.8.3"
},
"dependencies": {
"react": "16.13.1",
"react-dom": "16.13.1"
},
"staticFiles": {
"staticPath": "./src/public",
"watcherGlob": "**"
},
"babel": {
"presets": [
"env",
"react"
]
},
"scripts": {
"dev": "parcel src/index.html --no-cache",
"build": "parcel build src/index.html --no-cache",
"start": "pm2 start 'npm run dev' --name app",
"restart": "pm2 restart app",
"stop": "pm2 kill",
"logs": "pm2 logs"
}
}
edit file
components/AppUseState.tsx
:import { useState } from 'preact/hooks';
import * as React from 'preact/compat';
import { JSXInternal } from 'preact/src/jsx';
type Element = JSXInternal.Element;
export function AppUseState(): Element {
const [message, setMessage] = useState('Hello');
const reversed = (str: string) => str.split('').reverse().join('');
const toggleReverse = () => setMessage(reversed(message));
return <h1 onClick={toggleReverse}>
{ message } 📦 🚀
</h1>
}
edit file
main.tsx
:import * as Preact from 'preact';
import * as React from 'preact/compat';
import { AppUseState } from './components/AppUseState';
const { h, render } = Preact;
render(
<React.Fragment>
<p>useState:</p>
<AppUseState/>
<br/>
</React.Fragment>,
document.querySelector('#app')
);
done.