Technology Stack - ProjectEvergreen/create-evergreen-app GitHub Wiki
As the case usually is, we often do (and should!) rely on some external dependencies to assist in application development. Not everything should be done by hand, especially if it falls far outside the scope of delivering immediate business value.
Below are some key technologies that provide direct benefit to the development process, by making it easier to develop more robust applications while also lowering the risk of coupling too tightly to any one particular abstraction that isn't native to the web platform.
If you're interested in keeping an eye on new standards and browser features, checkout some of our issues we've made to follow those proposals, or submit your own!
We appreciate all contributions! 🙏
NodeJS is a command line interface for running JavaScript and boasts a robust ecosystem of great open source projects. Install the LTS version and verify that it, and its package manager npm are working, by running the following in your terminal:
$ node -v
$ npm -v
Yarn is my personal preference for Project Evergreen, so for contributors, please install it too.
It is recommended that npm scripts be used to capture common, development related workflows used in maintaining an application, like:
-
develop
- task for starting a development server with file change detection, live reload, HMR, etc -
build
- task for building a production version of the application -
test
a task for running tests
These scripts are defined in a project's package.json, like so:
{
"name": "my-app",
"version": "0.1.0",
"scripts": {
"build": "rimraf ./build && webpack --config webpack.config.prod.js",
"develop": "webpack-dev-server --config webpack.config.develop.js --open",
"serve": "yarn build && cd build && http-server"
},
"dependencies": {},
"devDependencies": {}
}
Run them from the command line in the root of the project
$ yarn develop
# or
$ npm run develop
Note: all developer dependencies should be saved locally to the project!
Yarn is a CLI package manager alternative to npm, which Project Evergreen favors. However, please consider npm first since it comes with NodeJS until you find issues (typically when running lots internal UI libraries and application's at scale). Either way, commit your .lock
file! 👌
webpack is a web application bundler designed to make the building of modern JavaScript applications easy and extensible for a developers, with a focus on performance and build optimization for users.
In particular, webpack has a robust ecosystem of plugins that can be used for optimizating and fine tuning a web application to take advantage of latest best practices like inlining critical CSS and building a Progressive Web Application.
Project Evergreen follows webpack's recommended best practice of splitting up configurations.
Babel transforms newer JavaScript features down to "older" JavaScript for those browsers that don't support the newer JavaScript features. babel-preset-env and babel-polyfill are used to ensure that transformations only happen for those specific browsers we are targetting that don't understand the newer JavaScript features we are using.
As browsers evolve automatically ("evergreen"), the build will evolve as well, to longer need to transpile down to older JavaScript if it becomes unnecessary. Shipping the newest code will always provide the best benefit to our users.
- Modules
- Classes
- Promises
- Web Components (Custom Elements / Shadow DOM / HTML Templates)
- Template Literal
-
Array[map,reduce,filter, etc]
,Map
,Set
- Fetch API
- Observables 🤞
Note: this example extends from
HTMLElement
// sample code
import { html, render } from 'lit-html';
import css from './footer.css';
class FooterComponent extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({ mode: 'closed' });
render(this.template(), this.root);
}
template() {
return html`
<style>
${css}
</style>
<footer>
<h3>© Project Evergreen 2018</h3>
</footer>
`;
}
}
customElements.define('x-footer', FooterComponent);
// Usage: <x-footer></x-footer>
PostCSS, like Babel for JavaScript (see above), transforms newer CSS to older CSS for those browsers that don't support the newer CSS features being used.
- Flexbox / CSS Grid
- Nested Selectors
-
@import
- CSS Variables
-
:host
and other new psuedo-selectors
/* sample code*/
:host {
display: flex;
justify-content: center;
text-align: center;
margin-bottom: 40px;
cursor: pointer;
& .header-text {
margin: 0 auto;
}
}
lit-html is a client side library that improves upon the JavaScript feature of tagged template literals by allowing the creation of HTML Templates (<templates>
) using JavaScript, that can then be efficiently rendered and re-rendered.
Note: We are currently evaluating the use of
lit-html-element
or other similar baseclass
solutions.
// example: HTML-in-JS (think of JSX)
import {html, render} from 'lit-html';
const HelloWorldComponent = (name) => {
const name = name || 'World';
return html`
<h1>Hello ${name}!</h1>
`;
}
render(HelloWorldComponent, document.getElementById('app'));
// example: consuming an external template (like for Vue / Angular), using webpack
import {html, render} from 'lit-html';
import HelloWorldComponentTemplate from '!to-string-loader!html-loader!./hello-world.template.html';
const HelloWorldComponent = (name) => {
const name = name || 'World';
return html`${HelloWorldComponentTemplate}`;
}
render(HelloWorldComponent, document.getElementById('app'));
This nicely compliments the Component Driven Development approach from the Styleguide, as well as the potential of not being needed when future specfications come along.
lit-html is not the only option here however, so check out some of the others if you want, like hyperHTML. Keep in mind that whatever library you use choose, that it sticks to the use of JavaScript template string literals.
We can also use lit-html to import our CSS! See the Component Driven Development guide above for examples!
Check out this great talk by Justin Fagnani about lit-html.
LitElement
is a base class provided by the Polymer team that provides some nice decoration on top of the raw HTMLTemplate
class and additionally provides some nice lifecycle hooks, like a _render()
method. It also exports html
from lit-html.
Here is an extended example using the HelloComponent
from above that accepts an input to display a greeting.
import { LitElement, html } from '@polymer/lit-element';
class GreetingComponent extends LitElement {
static get properties() {
return {
name: {
type: String,
attrName: 'name'
}
};
}
_render(props) {
return html`
<style>
:host .name {
color: green;
}
</style>
<h1>Hello <span class="name">${props.name}!</span></h1>
`;
}
}
customElements.define('x-greeting', GreetingComponent);
// Usage
// <x-greeting name="Owen"></x-greeting>
// TODO