Don't fork me!

Travis CI status: Build Status

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
build bundle
npm run build
verify result
npm i -g serve
serve dist/

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.