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