Blog address: Address

Github project address: address

Create a project

 $ mkdir example
 $ cd example
 $ npm init -yCopy the code

Creating a directory structure

├─ ├─ └─ config // ├─ package.json ├─ server ├─ ├─ SRC // Source file directoryCopy the code

Install Webpack

$ npm i --save-dev webpackCopy the code

Write a Webpack configuration file

Create a new file in the config directory:

$ cd config
$ touch webpack.config.dev.js
$ touch webpack.config.pro.jsCopy the code

Let’s start by writing webpack.config.dev.js in development

const path = require('path')
const webpack = require('webpack'Resolve (__dirname) // Source folder path const CONFIG_PATH = path.resolve(__dirname) // source folder path const APP_PATH = path.resolve(CONFIG_PATH,'.. /src'// APP_FILE const APP_FILE = path.resolve(APP_PATH,'index.js'Const BUILD_PATH = path.resolve(ROOT_PATH,'.. /dist'Module.exports = {// entry: APP_FILE, // output: {// tells Webpack where to store the result path: BUILD_PATH, // packaged filename filename:'bundle.js'// The path of templates, styles, scripts, images and other resources on the server publicPath:"/assets/",}}Copy the code

A simple WebPack configuration file is complete

Install Babel

We use ES6 for coding, so ES6 babel-Preset needs to be installed

$ npm i --save-dev babel-cli babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0Copy the code

Also modified the webpack configuration file to add:

module: {
  rules: [{
    test: /\.js$/,
    exclude: /node_modules/,
    loader: "babel-loader"}}]Copy the code

Add the babelrc file to the root directory

cd /path/to/example
touch .babelrcCopy the code

Modify babelrc.

{
  "env": {
    "development": {
      "presets" : ["es2015"."stage-0"."react"],},"production": {
      "presets" : [["es2015", { "modules": false."loose": true}]."stage-0"."react"],]}}}Copy the code

Installing other Loaders

  • css-loader

  • style-loader

  • postcss-loader

  • less-loader

  • file-loader

  • url-loader

  • autoprefixer

npm i --save-dev css-loader style-loader file-loader less less-loader postcss-loader url-loader autoprefixerCopy the code

Module. rules of module. Exports:

rules: [
  {
    test: /\.js$/,
    exclude: /node_modules/,
    loader: "babel-loader"
  },
  {
    test: /\.css$/,
    use: [
      'style-loader'.'css-loader',
      {
        loader: 'postcss-loader',
        options: {
          plugins: (loader) => [
            require('autoprefixer')()]}}]}, {test: /\.less$/,
    use: [
      'style-loader'.'css-loader',
      {
        loader: 'postcss-loader',
        options: {
          plugins: (loader) => [
            require('autoprefixer') (the)]}},'less-loader'] {},test: /\.(eot|woff|ttf|woff2|svg|gif)(\? |$)/, loader:'file-loader? name=[hash].[ext]'
  },
  {
    test: /\.(png|jpg)$/,
    loader: 'url-loader? limit=1200&name=[hash].[ext]'}]Copy the code

Local Node Service

Create server.js and index.html under server:

$ cd server
$ touch server.js
$ touch index.htmlCopy the code

Install server service dependencies

$ npm i --save expressCopy the code

Modify the server.js file

const app = new (require('express'// Const port = 3003 app.get()The '*'.function(req, res) {
  res.sendFile(__dirname + '/index.html')
})
​
app.listen(port, function(error) {
  if (error) {
    /*eslint no-console: 0*/
    console.error(error)
  } else {
    /*eslint no-console: 0*/
    console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port)
  }
})Copy the code

The simplest local preview service is complete

Hot update

We used react-hot-loader to do hot updates, webpack-dev-middleware, and webpack-hot-Middlewaref to refresh pages in real time

Install dependencies

$ npm i --save-dev react-hot-loader webpack-dev-middleware webpack-hot-middlewareCopy the code

Write index. HTML

<! DOCTYPE html> <html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, viewport-fit=contain"/>
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title></title>
</head>
<body ontouchstart="">
  <div id="app"></div>
  <script src="/assets/bundle.js"></script>
</body>
</html>
​Copy the code

Modify server. Js

const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackHotMiddleware = require('webpack-hot-middleware')
const config = require('.. /config/webpack.config.dev.js')
const app = new (require('express'))() const port = 3003 const compiler = webpack(config) app.use(webpackDevMiddleware(compiler, {noInfo:true,
  publicPath: config.output.publicPath,
  stats: {
    colors: true
  }
}))
​
app.use(webpackHotMiddleware(compiler))
​
app.get(The '*'.function(req, res) {
  res.sendFile(__dirname + '/index.html')
})
​
app.listen(port, function(error) {
  if (error) {
    /*eslint no-console: 0*/
    console.error(error)
  } else {
    /*eslint no-console: 0*/
    console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port)
  }
})Copy the code

Modify entry for module.exports of webpack.config.dev.js

entry: [
    'react-hot-loader/patch'// reload=trueIf it can't be hot reload, refresh the page.'webpack-hot-middleware/client? reload=true',
    APP_FILE
],Copy the code

Exports added:

plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('development'}})) / / define compile environment, new webpack. HotModuleReplacementPlugin (), new webpack. NoEmitOnErrorsPlugin ()],Copy the code

Add preset in the babelrc file

"plugins" : ["react-hot-loader/babel"]Copy the code

.babelrc

Final code:

{
  "env": {
    "development": {
      "presets" : ["es2015"."stage-0"."react"]."plugins" : ["react-hot-loader/babel"]},"production": {
      "presets" : [["es2015", { "modules": false."loose": true}]."stage-0"."react"].}}}Copy the code

webpack.config.dev.js

Final code:

/**
 * @author Chan Zewail
 * ###### Thu Jan 25 19:28:40 CST 2018
 */
const path = require('path')
const webpack = require('webpack'Resolve (__dirname) // Source folder path const CONFIG_PATH = path.resolve(__dirname) // source folder path const APP_PATH = path.resolve(CONFIG_PATH,'.. /src'// APP_FILE const APP_FILE = path.resolve(APP_PATH,'index.js'Const BUILD_PATH = path.resolve(ROOT_PATH,'.. /dist')
​
module.exports = {
  entry: [
    'react-hot-loader/patch'// reload=trueIf it can't be hot reload, refresh the page.'webpack-hot-middleware/client? reload=true', APP_FILE], output: {// tells Webpack where to store the result.'bundle.js'// The path of templates, styles, scripts, images and other resources on the server publicPath:"/assets/",
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader"
      },
      {
        test: /\.css$/,
        use: [
          'style-loader'.'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: (loader) => [
                require('autoprefixer')()]}}]}, {test: /\.less$/,
        use: [
          'style-loader'.'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: (loader) => [
                require('autoprefixer') (the)]}},'less-loader'] {},test: /\.(eot|woff|ttf|woff2|svg|gif)(\? |$)/, loader:'file-loader? name=[hash].[ext]'
      },
      {
        test: /\.(png|jpg)$/,
        loader: 'url-loader? limit=1200&name=[hash].[ext]'
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('development'}})) / / define compile environment, new webpack. HotModuleReplacementPlugin (), new webpack. NoEmitOnErrorsPlugin ()], resolve: {// Auto-complete extensions: ['.js'.'.jsx'.'.less'.'.scss'.'.css'], // Root path aliasalias: {
      The '@': `${APP_PATH}/`,
    },
    modules: [
      'node_modules'.'src',]}}Copy the code

NPM script command

Install some tool dependencies

npm i --save-dev copyfiles clean-webpack-pluginCopy the code

Add to package.json:

"scripts": {
    "dev": "node server/server.js"."start": "npm run dev"."copy": "copyfiles -f ./server/index.html ./dist"."build": "npm run copy && webpack --config config/webpack.config.pro.js"
},Copy the code

Start coding the project

Install the react

npm i --save react react-domCopy the code

Entrance to the file

$ cd src
# import file
$ touch index.js
# Application file
$ touch App.jsCopy the code

Write index. Js

import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'// Import App from'./App'
​
ReactDOM.render(
  <AppContainer>
    <App/>
  </AppContainer>
  , document.getElementById('app') // Hot updateif (module.hot) {
  module.hot.accept('./App', () => {
    const NextApp = require('./App').default
    ReactDOM.render(
      <AppContainer>
        <NextApp/>
      </AppContainer>,
      document.getElementById('app'))})}Copy the code

Buckets of

  • react

  • react-dom

  • react-router

  • redux

  • redux-saga

  • redux-persist

  • history

  • redux-logger

  • react-router-redux

npm i --save react-router redux redux saga reux-persist history redux-logger react-router-reduxCopy the code

Write configureStore generate store,

$ cd src
$ mkdir store
$ touch index.jsCopy the code
/**
 * @author Chan Zewail
 * ###### Thu Jan 25 19:28:40 CST 2018
 */
import { createStore, applyMiddleware, compose } from 'redux'
import { persistStore } from 'redux-persist'
import reducers from '@/reducers'
import createHistory from 'history/createHashHistory'
import { routerMiddleware } from 'react-router-redux'
import createSagaMiddleware from 'redux-saga'
import sagas from '@/sagas'
import logger from 'redux-logger'/ / createhistory
export const historyConst middleWares = [createHistory() // createSagaMiddleware const sagaMiddleware = createSagaMiddleware() // sagaMiddleware, routerMiddleware(history), logger] // Generate store const store = createStore(reducers, undefined, compose(applyMiddleware(... MiddleWares),)) // Stores store data in cache const persistor = persistStore(store, null) // generates the final store functionexport default function configureStore(){// Run saga sagamiddleware.run (sagas)return { persistor, store }
}
​
export function getPersistor() {
  return persistor
}
​Copy the code

Write the reducer

$ cd src
$ mkdir reducers
$ touch index.jsCopy the code
/**
 * @author Chan Zewail
 * ###### Thu Jan 25 19:28:40 CST 2018
 */
import { routerReducer } from 'react-router-redux'
import { persistCombineReducers, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
// import xxxReducer from './xxx'/ / story - persist configurationexport const config = {
  key: 'root',
  storage,
  debug: trueWhitelist saved to the local cache by the reducer: ['routing'} // Merge reducerexportDefault persistCombineReducers(config, {routing: routerReducer, // XXX: xxxReducer,})Copy the code

Write the saga

$ cd src
$ mkdir sagas
$ touch index.jsCopy the code
/**
 * @author Chan Zewail
 * ###### Thu Jan 25 19:28:40 CST 2018
 */
import { fork, all } from 'redux-saga/effects'
// import xxxSagaFlow from './xxxFlow'/ / root sagaexport default function* rootSaga () {
  yield all([
    // fork(xxxSagaFlow)
  ])
}
​Copy the code

App.js

/**
 * @author Chan Zewail
 * ###### Thu Jan 25 19:28:40 CST 2018
 */
import React from 'react'
import { Provider } from 'react-redux'
import { history } from '@/store'
import { ConnectedRouter } from 'react-router-redux'
import { PersistGate } from 'redux-persist/es/integration/react'
import { Redirect } from 'react-router-dom'// Method called before persister cache recovers const onBeforeLift = () => {// console.log()'before action')
}
​
class App extends React.Component {
  constructor(props) {
    super(props)
  }
​
  render() {const {persistor, store} = this.propsreturn (
      <Provider store={store}>
        <PersistGate loading={<div/>} onBeforeLift={onBeforeLift} persistor={persistor}>
          <ConnectedRouter history= {history}>
            // switch and route
          </ConnectedRouter>
        </PersistGate>
      </Provider>
    )
  }
}
​
export default App
​Copy the code

Modify index.js and add the get Store method and pass it to the props of App (Hot Update Store)

index.js

/**
 * @author Chan Zewail
 * ###### Thu Jan 25 19:28:40 CST 2018
 */
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import configureStore from '@/store'// Home page import App from'./App'export const stores = configureStore()
​
ReactDOM.render(
  <AppContainer>
    <App stores={stores}/>
  </AppContainer>
  , document.getElementById('app') // Hot updateif (module.hot) {
  module.hot.accept('./App', () => {
    const NextApp = require('./App').default
    ReactDOM.render(
      <AppContainer>
        <NextApp stores={stores}/>
      </AppContainer>,
      document.getElementById('app'))})}Copy the code

The last

The react family bucket is already in place, and other features can be added and customized over time

Final code: github.com/czewail/zew…

Use questions can be raised in Issues

Welcome to the Start