Skip to content
This repository has been archived by the owner on Jun 28, 2022. It is now read-only.

Commit

Permalink
Merge pull request #75 from Lapanti/feature/replace-browserify-with-w…
Browse files Browse the repository at this point in the history
…ebpack

(#37): Move from Browserify to Webpack
  • Loading branch information
lapanti committed Jan 15, 2018
2 parents 3716a33 + abb84a0 commit d6b3924
Show file tree
Hide file tree
Showing 18 changed files with 3,004 additions and 849 deletions.
4 changes: 4 additions & 0 deletions .babelrc
@@ -0,0 +1,4 @@
{
"presets": ["babel-preset-env"],
"plugins": ["react-hot-loader/babel"]
}
30 changes: 16 additions & 14 deletions README.md
@@ -1,7 +1,7 @@
# A very opinionated frontend boilerplate

[![Greenkeeper badge](https://badges.greenkeeper.io/Lapanti/ts-react-boilerplate.svg)](https://greenkeeper.io/)
[![Build Status](https://img.shields.io/travis/Lapanti/ts-react-boilerplate/master.svg?style=flat-square)](https://travis-ci.org/Lapanti/ts-react-boilerplate) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT) [![Dependency Status](https://david-dm.org/lapanti/ts-react-boilerplate.svg?style=flat-square)](https://david-dm.org/lapanti/ts-react-boilerplate) [![DevDependency Status](https://img.shields.io/david/dev/lapanti/ts-react-boilerplate.svg?style=flat-square)](https://david-dm.org/lapanti/ts-react-boilerplate?type=dev) [![Coverage Status](https://img.shields.io/coveralls/Lapanti/ts-react-boilerplate/master.svg?style=flat-square)](https://coveralls.io/github/Lapanti/ts-react-boilerplate?branch=master)[![Code Climate](https://img.shields.io/codeclimate/github/Lapanti/ts-react-boilerplate.svg?style=flat-square)](https://codeclimate.com/github/Lapanti/ts-react-boilerplate) [![Code Climate](https://img.shields.io/codeclimate/issues/github/Lapanti/ts-react-boilerplate.svg?style=flat-square)](https://codeclimate.com/github/Lapanti/ts-react-boilerplate/issues)
[![Build Status](https://img.shields.io/travis/Lapanti/ts-react-boilerplate/master.svg?style=flat-square)](https://travis-ci.org/Lapanti/ts-react-boilerplate) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT) [![Dependency Status](https://david-dm.org/lapanti/ts-react-boilerplate.svg?style=flat-square)](https://david-dm.org/lapanti/ts-react-boilerplate) [![DevDependency Status](https://img.shields.io/david/dev/lapanti/ts-react-boilerplate.svg?style=flat-square)](https://david-dm.org/lapanti/ts-react-boilerplate?type=dev) [![Coverage Status](https://img.shields.io/coveralls/Lapanti/ts-react-boilerplate/master.svg?style=flat-square)](https://coveralls.io/github/Lapanti/ts-react-boilerplate?branch=master) [![Code Climate](https://img.shields.io/codeclimate/issues/github/Lapanti/ts-react-boilerplate.svg?style=flat-square)](https://codeclimate.com/github/Lapanti/ts-react-boilerplate/issues)

## Purpose

Expand Down Expand Up @@ -37,11 +37,10 @@ This is all you need to get started in developing your own web application, usin
1. Open up the source code in your favorite TypeScript-capable editor (I recommend [Visual Studio Code](https://code.visualstudio.com/) if you don't have a preference)
2. Run `yarn` in the console to install dependencies (it'll take a while on the first run, so go on and read ahead while you wait)
3. Read through the comments in all the source files to get yourself acquinted with the ideas, concepts and patterns
4. Start the application by running `yarn run develop` in your console (inside the folder you downloaded the code to) and open up your browser in the address it prints out
- If you want the use of [LiveReload](http://livereload.com/), install a browser extension in [Chrome](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei?hl=en) or [Firefox](https://addons.mozilla.org/en-gb/firefox/addon/livereload/)
5. Create a deployable version of the application by running `yarn run build`
6. Start the deployable version by running `yarn run start` or read the [How to Docker](#dockerization) guide to Dockerize your application
7. To test your application, run `yarn run test`
4. Start the application by running `yarn develop` in your console (inside the folder you downloaded the code to) and open up your browser in the address it prints out
5. Create a deployable version of the application by running `yarn build`
6. Start the deployable version by running `yarn start` or read the [How to Docker](#dockerization) guide to Dockerize your application
7. To test your application, run `yarn test`
8. Start modifying the code to build your own application

## <a name="tipsandsuggestions">Tips and suggestions</a>
Expand All @@ -68,16 +67,19 @@ The following are all the dependencies of the project, with the reasoning behind
- :gift: [Redux](https://github.com/reactjs/redux) to handle state
- :loop: [redux-observable](https://redux-observable.js.org/) to allow side-effects in Redux
- :mag: [RxJs](https://github.com/ReactiveX/RxJS) for streams
- :electric_plug: [browserify](http://browserify.org/) to bundle JS files
- :flashlight: [budō](https://github.com/mattdesl/budo) to host client while developing
- :punch: [tsify](https://github.com/TypeStrong/tsify) to compile TypeScript in the browserify pipe
- :electric_plug: [webpack](https://webpack.js.org/) to bundle JS files
- :flashlight: [webpack-dev-server](https://webpack.js.org/configuration/dev-server/#src/components/Sidebar/Sidebar.jsx) to host client while developing
- :punch: [awesome-typescript-loader](https://github.com/s-panferov/awesome-typescript-loader) to compile TypeScript in the webpack pipe
- :wave: [babel](https://babeljs.io) to transpile our compiled JavaScript to ES5 using [babel-loader](https://webpack.js.org/loaders/babel-loader/#src/components/Sidebar/Sidebar.jsx)
- :tongue: [sass-loader](https://webpack.js.org/loaders/sass-loader/#src/components/Sidebar/Sidebar.jsx) to compile SASS into CSS
- :pray: [Jest](https://facebook.github.io/jest/) for testing
- :metal: [ts-jest](https://github.com/kulshekhar/ts-jest) to run Jest with TypeScript
- :ok_hand: [TSlint](https://palantir.github.io/tslint/) for linting
- :runner: [nock](https://github.com/node-nock/nock) to mock API calls
- :question: [sass-lint](https://github.com/sasstools/sass-lint) to lint SASS
- :bust_in_silhouette: [Enzyme](https://github.com/airbnb/enzyme) for snapshot and behavior testing
- :cyclone: [Enzyme-to-JSON](https://github.com/adriantoine/enzyme-to-json) to enable Enzyme snapshots with Jest
- :foggy: [enzyme-adapter-react-16](https://github.com/airbnb/enzyme/tree/master/packages/enzyme-adapter-react-16) to use Enzyme with React 16
- :nail_care: [SASS](https://github.com/sass/node-sass) for styles
- :two_hearts: [concurrently](https://github.com/kimmobrunfeldt/concurrently) to run multiple script concurrently

Expand All @@ -89,15 +91,15 @@ Read the [contribution guidelines](./CONTRIBUTING.md)
2. Navigate to the directory in console
3. Run `yarn` in console
- [Optional] Install livereload extension to your browser in [Chrome](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei?hl=en) or [Firefox](https://addons.mozilla.org/en-gb/firefox/addon/livereload/)
4. Run `yarn run develop` in console
4. Run `yarn develop` in console
5. Open your browser in the address printed to the console
6. Modify the code with your favorite editor

### <a name="testing">Testing</a>
- You can run all the tests with `yarn run test`
- *psst, you can update your snapshots with* `yarn run test -- -u`
- You can run Jest tests in watch mode with `yarn run test:watch`
- You can run all tests with coverage with `yarn run test:ci`
- You can run all the tests with `yarn test`
- *psst, you can update your snapshots with* `yarn test -- -u`
- You can run Jest tests in watch mode with `yarn test:watch`
- You can run all tests with coverage with `yarn test:ci`

### <a name="roadmap">Roadmap</a>

Expand Down
1 change: 1 addition & 0 deletions SUMMARY.md
Expand Up @@ -12,6 +12,7 @@
* [Reducers](/docs/REDUCERS.md)
* [Containers](/docs/CONTAINERS.md)
* [Completing React](/docs/COMPLETING.md)
* [webpack](/docs/WEBPACK.md)
* [Styles](/docs/STYLES.md)
* [Testing](/docs/TESTING.md)
* [Extras](/docs/EXTRAS.md)
109 changes: 52 additions & 57 deletions docs/COMPLETING.md
Expand Up @@ -74,55 +74,77 @@ import * as ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Route } from 'react-router-dom';
import { ConnectedRouter } from 'react-router-redux';
import { AppContainer as HotContainer } from 'react-hot-loader';
import createHistory from 'history/createBrowserHistory';
import configureStore from './redux/store';
import AppContainer from './modules/AppContainer';

const history = createHistory();

ReactDOM.render((
<Provider store={configureStore(history)}>
<ConnectedRouter history={history}>
<Route component={AppContainer} />
</ConnectedRouter>
</Provider>
), document.getElementById('app'),
const render = (container: React.ComponentClass) => ReactDOM.render(
<HotContainer>
<Provider store={configureStore(history)}>
<ConnectedRouter history={history}>
<Route component={container} />
</ConnectedRouter>
</Provider>
</HotContainer>,
document.getElementById('app'),
);

render(AppContainer);

if ((module as any).hot) {
(module as any).hot.accept('./modules/AppContainer', () => render(AppContainer));
}

```
which is the entry file to our application that ties everything together.

---

On the 12. line
On the 14. line
```typescript
import * as ReactDOM from 'react-dom';

ReactDOM.render((
// ...
), document.getElementById('app'),
const render = (container: React.ComponentClass) => ReactDOM.render(
// ...,
document.getElementById('app'),
))
```
we [render](https://facebook.github.io/react/docs/react-dom.html#render) our **React**-application to the **DOM** inside a div with the id `app` (*we'll come back to this*).

---

On the 13. line
On the 15. line
```typescript
import { AppContainer as HotContainer } from 'react-hot-loader';
// ...
<HotContainer>
// ...
</HotContainer>,
```
we wrap our application into a container to enable **Hot Module Replacement** (more about it later in this section).

---

On the 16. line
```typescript
import * as React from 'react';
import { Provider } from 'react-redux';
import createHistory from 'history/createBrowserHistory';
import configureStore from './redux/store';
const history = createHistory();
// ...
<Provider store={configureStore(history)}>
// ...
</Provider>
<Provider store={configureStore(history)}>
// ...
</Provider>
```
which wraps our **React** application with **Redux** using [`Provider`](https://github.com/reactjs/react-redux/blob/master/docs/api.md#provider-store) from **react-redux**, which takes a single parameter `store`, for which we provide our store as we defined it in [Redux](/REDUX.md#store). `history/createBrowserHistory` is used to create a wrapper around the browser history we can use.

---

On the 14. line
On the 17. line
```typescript
import * as React from 'react';
import { Route } from 'react-router-dom';
Expand All @@ -136,57 +158,30 @@ import AppContainer from './modules/AppContainer';
```
we keep the UI in sync with the URL using a [`ConnectedRouter`](https://github.com/ReactTraining/react-router/tree/master/packages/react-router-redux) from **react-router-redux**, which takes as argument a [`history`](https://github.com/ReactTraining/react-router/blob/v3/docs/API.md#histories), where we give `history` we created previously. Here we define a single `Route` which renders `AppContainer` for all URL routes.

---

Finally at the end
```typescript
if ((module as any).hot) {
(module as any).hot.accept('./modules/AppContainer', () => render(AppContainer));
}
```
we do a little configuration to allow our container to be loaded by the **Hot Module Replacement**-system.

### Index.html

Finally we write an `index.html` in our root-folder
```html
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Todo app</title>
<title>TS-React boilerplate</title>
</head>
<body>
<div id="app"></div>
<script src="js/bundle.js"></script>
<script src="/bundle.js"></script>
</body>
</html>
```
which is just a very simple `HTML`-file, which imports our (*soon-to-be-bundled*) **JavaScript** from the path `/js/bundle.js` and contains a `div` with the id `app` so our `index.ts` works.

### Scripts

Now as we have everything necessary for our application, it's time to get it working!

We'll begin by installing a couple of new dependencies
```
yarn add -D browserify budo tsify
```
from which [browserify](http://browserify.org/) allows us to do `import`-statements in client code, [budō](https://github.com/mattdesl/budo) is a lightweight server to host client code (*it uses browserify under the hood*) and [tsify](https://www.npmjs.com/package/tsify) is a **browserify**-plugin to use it with **TypeScript**.

---

First it's time to write our development script, so head on over to your `package.json` and add the following
```json
// ...
"scripts": {
"develop": "budo src/index.tsx:js/bundle.js --live --verbose -- -p tsify"
}
```
which allows you to start the **budō** server by entering `yarn run develop` into your console (*inside the root folder of your app*). It will run until it faces an error it can't recover from or you press `ctrl+c`. The arguments given to **budō** are firstly, the name of your application entry file (*with a relative path*), followed by a double colon with the path and name of your `index.html` (*relative to root folder*) expects to find your application code. `--live` enables [LiveReload](http://livereload.com/) (*you can install a plugin to [Chrome](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei?hl=en) or [Firefox](https://addons.mozilla.org/en-gb/firefox/addon/livereload/) to take full advantage of it*), which automatically refreshes your browser when the source code changes. `--verbose` enables verbose output from **budō** and then all arguments after the ` -- ` will go to the **browserify** **budō** is running, in this case a plugin **tsify** to compile our **TypeScript** files.

---

Now it's time to build our application to be hosted on the Internet, so add the following line to your `scripts` inside `package.json`
```json
// ...
"scripts": {
// ...
"build": "mkdir -p dist/js && browserify src/index.tsx -p tsify > dist/js/bundle.js"
}
```
which will first make sure that the folder `dist/js` is there and then build your application with **browserify**. For **browserify** we give as first argument the entry file, then a plugin (*again, **tsify** to use **TypeScript** with **browserify***) and finally after the `>` the output file name (*with its relative path*). Apart from this script (*run by `yarn run build`*) you only need to copy your `index.html` file to the `dist`-folder and your application is complete!

### Alternatives

- An alternative for **browserify** is [webpack](https://webpack.github.io/), which is maybe a bit more popular these days, but I personally dislike the amount of configuration (*and the way the configuration is achieved*) it requires
which is just a very simple `HTML`-file, which imports our (*soon-to-be-bundled*) **JavaScript** from the current folder `/bundle.js` and contains a `div` with the id `app` so our `index.ts` works.

0 comments on commit d6b3924

Please sign in to comment.