Currently Project Evergreen is using a combination of **webpack**, **Babel**, and **PostCSS** in the reference app projects in its GitHub organization.
> **Note:** More [thorough investigation](https://github.com/ProjectEvergreen/project-evergreen/issues/25) needs to be done to determine the pros / cons of using a module bundler vs shipping straight Modules.
>
> General approach by Project Evergreen presently is to use a module bunder (**webpack**) + long term caching + HTTP/2.
## Evergreen Build
### weback
[**webpack**](https://webpack.js.org/) is a module bundler for web applications. Out of the box it provides a lot of support for optimizing and code splitting JavaScript as well as managing many other assets types (like CSS, HTML, images, fonts, etc). It's principal function is it to understand the relationship of all the `import`s in your app so as to then be able to generate an optimized static build from that.
It also supports a robust community and ecosystem that allows the **webpack** bundling process to be extended to support many other important build related tasks, like:
- Templating file paths into an _index.html_ file
- Generating Favicons
- Inlining Critical CSS
- Seamless integration with transpilation tools (like **Babel** and **PostCSS**)
#### How it Works
Esssentially, webpack works by being configured with an "entry" point file that contains the JavaScript needed to start your application, the "main" method if you will.
> Learn more about webpack concepts [here](https://webpack.js.org/concepts/)
A sample webpack configuration might look like this:
```javascript
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: {
index: './index.jsx'
},
output: {
path: path.resolve(__dirname, './build'),
filename: '[name].[chunkhash].bundle.js',
sourceMapFilename: '[name].map',
chunkFilename: '[id].[chunkhash].js'
},
module: {
rules: [{
test: /\.(js*)$/,
enforce: 'pre',
loader: 'eslint-loader'
}, {
test: /\.(js*)x$/,
loaders: [
'babel-loader'
]
}, {
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff'
}, {
test: /\.(ttf|eot|svg|jpe?g|png|gif|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader'
}]
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
chunksSortMode: 'dependency'
})
]
};
```
1. The "entry" file serves as the start of the dependency graph **webpack** will build up, following every `import` (including your _node modules_)
1. Each file (by extension type) will get processed according to the configuration defined in `module.rules`, by a "`loader`". Loaders tell **webpack** how to process a given file. (converting LESS -> CSS, TypeScript -> JavaScript, )
1. After all files have been processed, **webpack** will generate a compilation (an in memory representation of the final static output), and then run the plugins defined in `plugins`
1. In the above example, **HtmlWebpackPlugin** will take the file paths from the compilation generated by **webpack** and have those paths inserted into a given _index.html_ file. No more having to manage paths in `
```
#### ES5 / ES2015+ Support
Older browsers will likely not have all JavaScript features supported (like [`Function.proptype.toString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/toString)) and such will need polyfills.
```html
```
#### ES5 Adapter
However, if transpiling down to ES5 and because Custom Elements v1 must be `class` based, transpiling these v0 Custom Elements will break in modern browsers. This means a shim must be put in place to wrap these Custom Elements so they will This
```html
```
> 📝 The error is known issue, as the `()` is used for progressive feature detection.
### ESLint
Code quality and a consistent styleguide are important for any application. It's not so much about which is better, tabs or spaces for example, but rather which one everyone can agree to for the sake of the project, and then locking that style in with [ESLint](https://eslint.org/). We encourage making it a team effort so buy in can be assured from all contributors.
#### .eslintrc
Keep your _.eslintrc_ file in the root of the project. Rather than show a sample config, here are some recommended configs to get you started:
- [Project Evergreen](https://github.com/ProjectEvergreen/todo-app/blob/master/.eslintrc)
## General Quickstart
To target modern browsers using **webpack**, **Babel**, **PostCSS**, and **LitElement** see the below steps. IE Instructions included at the end.
1. Install Dependencies (Yarn / npm)
Install the following tools via Yarn / npm to get a _package.json_ like this:
```json
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"babel-loader": "^8.0.1",
"babel-plugin-transform-builtin-classes": "^0.6.1",
"css-loader": "^0.28.11",
"css-to-string-loader": "^0.1.3",
"cssnano": "^3.10.0",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0",
"postcss-cssnext": "^3.1.0",
"postcss-loader": "^2.1.5",
"url-loader": "^1.0.1",
"webpack": "^4.8.3",
"webpack-cli": "^2.1.3",
"webpack-dev-server": "^3.1.4",
"webpack-merge": "^4.1.2"
```
1. Setup **webpack**
```javascript
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
context: path.resolve('./src'),
mode: 'production',
/* start writing some code at src/index.js! */
entry: {
index: './index'
},
output: {
filename: '[name].[chunkhash].bundle.js'
},
module: {
rules: [{
test: /\.js$/,
loader: 'babel-loader'
}, {
test: /\.css$/,
use: ['css-to-string-loader', 'css-loader', 'postcss-loader']
}, {
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff'
}, {
test: /\.(ttf|eot|svg|jpe?g|png|gif|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader'
}]
},
plugins: [
new HtmlWebpackPlugin({
chunksSortMode: 'dependency'
})
]
};
```
1. Setup **Browserslist** (_.browserslistrc_)
```shell
> 1%
not op_mini all
not ie 11
```
1. Setup Babel (_babel.config.js_)
```javascript
module.exports = {
presets: ['@babel/preset-env'],
/*
* needed for LitElement
* https://github.com/WebReflection/babel-plugin-transform-builtin-classes
*/
plugins: [
['babel-plugin-transform-builtin-classes', {
globals: ['LitElement']
}]
]
};
```
1. Setup PostCSS (_postcss.config.js_)
```javascript
module.exports = {
plugins: {
'postcss-cssnext': {},
'cssnano': {}
}
};
```
1. Setup Polyfills
```html
```
### For IE11
1. In _.browserslistrc_, allow IE 11
```
> 1%
not op_mini all
```
1. Include ES5 / ES2015+ polyfills for IE 11 and forward op of ES5 / v0 Custom Element
```html
```
## Recommended Documentation
- [Technology Stack](Technology-Stack)
- [Starting A New Project](Guide-Starting-A-New-Project)
- [Creating A Web Component](Guide-Creating-A-Web-Component)