1. 創建文件夾react-family并進入
2. npm init -y 生成package.json
3.安裝webpack
3.1 npm install --save-dev?webpack
3.2 創建webpack.dev.config.js
const?path?=?require('path')
module.exports?=?{??
????/*?入口?*/??
????entry:?path.join(__dirname,?'src/index.js'),??
????/*?輸出到dist文件夾,輸出文件名字為bundle.js?*/??
????output:?{????
????????path:?path.join(__dirname,?'./dist'),
????????filename:?'bundle.js'??
????}
}
3.3 新建入口文件
創建src文件夾,并在src下添加index.js文件
document.getElementById(‘app’).innerHTML = “Webpack!”
3.4 執行命令 webpack --config webpack.dev.config.js
生成了dist文件夾和bundle.js,在dist文件添加index.html文件,并引入bundle.js,在瀏覽器打開index.html,可以看到Webpack!
4?Babel
Babel 把用最新標準編寫的 JavaScript 代碼向下編譯成可以在今天隨處可用的版本。 這一過程叫做“源碼到源碼”編譯, 也被稱為轉換編譯。
babel-core 調用Babel的API進行轉碼
babel-loader
babel-preset-es2015 用于解析 ES6
babel-preset-react 用于解析 JSX
babel-preset-stage-0 用于解析 ES7 提案
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0
其中babel-loader 8.1.0版本和?babel-core 6.26.3版本不兼容,可以babel-loader改為7版本
新建babel配置文件.babelrc
{
??"presets":?[
????"es2015",
????"react",
????"stage-0"
??],
??"plugins":?[]
}
修改webpack.dev.config.js,增加babel-loader!
module:?{
????rules:?[{
????????test:?/\.js$/,
????????use:?['babel-loader?cacheDirectory=true'],
????????include:?path.join(__dirname,?'src')
????}]
??}
測試下,修改入口文件 src/index.js
var?func?=?str?=>?{
??document.getElementById('app').innerHTML?=?str
}
func('我現在在使用Babel!')
執行打包命令webpack --config webpack.dev.config.js
瀏覽器打開index.html,我們看到正確輸出了我現在在使用Babel!
打開打包后的bundle.js,可以看到箭頭函數被轉換成普通函數了!
5 react
npm install --save react react-dom
添加Hello組件? src/components/Hello/Hello.js
import?React,?{?Component?}?from?'react'
export?default?class?Hello?extends?Component?{
??render?()?{
????return?(
??????<div>
????????hello?react
??????</div>
????)
??}
}
修改入口文件?src/index.js使用react
import React from 'react';
import ReactDom from 'react-dom';
import Hello from './components/Hello/Hello';
ReactDom.render(
? ? <Hello/>, document.getElementById('app'));
打包webpack --config webpack.dev.config.js,打開index.html查看效果
6 命令優化
每次打包都得執行長命令webpack –config webpack.dev.config.js,所以我們優化下
修改package.json里面的script,增加dev-build
"scripts":?{
????"test":?"echo?\"Error:?no?test?specified\"?&&?exit?1",
????"dev-build":?"webpack?--config?webpack.dev.config.js"
??},
現在我們打包只需要執行npm run dev-build
7 react-router
cnpm install --save react-router-dom
新建兩個頁面
// src/pages/Home/Home.js
import?React,?{?Component?}?from?'react'
export?default?class?Home?extends?Component?{
??render?()?{
????return?(
??????<div>
????????this?is?home
??????</div>
????)
??}
}
// src/pages/ Page1/Page1.js?
import?React,?{?Component?}?from?'react'
export?default?class? Page1 extends?Component?{
??render?()?{
????return?(
??????<div>
????????this?is??page1
??????</div>
????)
??}
}
//? src/router/router.js
import?React?from?'react'
import?{?BrowserRouter?as?Router,?Route,?Switch,?Link?}?from?'react-router-dom'
import?Home?from?'../pages/Home/Home'
import?Page1?from?'../pages/Page1/Page1'
const?getRouter?=?()?=>?(
??<Router>
????<div>
??????<ul>
????????<li><Link?to='/'>首頁</Link></li>
????????<li><Link?to='/page1'>Page1</Link></li>
??????</ul>
??????<Switch>
????????<Route?exact?path='/'?component={Home}?/>
????????<Route?path='/page1'?component={Page1}?/>
??????</Switch>
????</div>
??</Router>
)
export?default?getRouter
修改入口文件src/index.js,引用Router
import?ReactDom?from?'react-dom'
import?getRouter?from?'./router/router'
ReactDom.render(
??getRouter(),?document.getElementById('app'))
8 webpack-dev-server
cnpm install webpack-dev-server@2 --save-dev
(版本2不會報錯)
修改webpack.dev.config.js,增加webpack-dev-server的配置。
devServer:?{
????contentBase:?path.join(__dirname,?'./dist'),
????historyApiFallback:?true,
????host:?'0.0.0.0',
????port:?8765
??}
現在執行 webpack-dev-server --config webpack.dev.config.js
瀏覽器打開http://localhost:8765,可以頁面路由切換了
修改package.json里面的script,增加start
"start":?"webpack-dev-server?--config?webpack.dev.config.js",
color(CLI only) console中打印彩色日志
historyApiFallback 任意的404響應都被替代為index.html。有什么用呢?你現在運行npm start,然后打開瀏覽器,訪問http://localhost:8080,然后點擊Page1到鏈接http://localhost:8080/page1,
然后刷新頁面試試。是不是發現刷新后404了。為什么?dist文件夾里面并沒有page1.html,當然會404了,所以我們需要配置
historyApiFallback,讓所有的404定位到index.html。
host 指定一個host,默認是localhost。如果你希望服務器外部可以訪問,指定如下:host: “0.0.0.0”。比如你用手機通過IP訪問。
hot 啟用Webpack的模塊熱替換特性。
port 配置要監聽的端口。默認就是我們現在使用的8080端口。
proxy 代理。比如在 localhost:3000 上有后端服務的話,你可以這樣啟用代理:
proxy:?{
? ? '/api':?'地址'
}
progress(CLI only) 將編譯進度輸出到控制臺。
9 模塊熱替換(Hot Module Replacement)
當我們修改代碼的時候,瀏覽器會自動刷新,為了修改代碼的時候,瀏覽器不會刷新。
修改package.json 增加 –hot
"start":?"webpack-dev-server?--config?webpack.dev.config.js?--color?--progress?--hot",
src/index.js 增加module.hot.accept(), 當模塊更新的時候,通知index.js。
import?ReactDom?from?'react-dom'
import?getRouter?from?'./router/router'
if?(module.hot)?{
??module.hot.accept()
}
ReactDom.render(
??getRouter(),?document.getElementById('app'))
執行npm run start,修改Home.js, 在不刷新頁面的情況下,內容更新了
但是當模塊熱替換的時候,state會重置
// src/pages/Home/Home.js
import?React,?{?Component?}?from?'react'export?default?class?Home?extends?Component?{
??constructor?(props)?{
????super(props)
????this.state?=?{
??????count:?0
????}
??}
??_handleClick?()?{
????this.setState({
??????count:?++this.state.count
????})
??}
??render?()?{
????return?(
??????<div>
????????this?is?home~<br?/>
????????當前計數:{this.state.count}<br?/>
????????<button?onClick={()?=>?this._handleClick()}>自增</button>
??????</div>
????)
??}
}
當我們修改代碼的時候,webpack在更新時候,也把count初始為0了
為了在react模塊更新的同時,能保留state等頁面中其他狀態,我們需要引入react-hot-loader
cnpm install react-hot-loader --save-dev
修改.babelrc 增加 react-hot-loader/babel
{
??"presets":?[
????"es2015",
????"react",
????"stage-0"
??],
??"plugins":?[
????"react-hot-loader/babel"
??]
}
webpack.dev.config.js入口增加react-hot-loader/patch
entry:?[
????'react-hot-loader/patch',
????path.join(__dirname,?'src/index.js')
??]
修改src/index.js
import?React?from?'react'
import?ReactDom?from?'react-dom'
import?{?AppContainer?}?from?'react-hot-loader'
import?getRouter?from?'./router/router'
/*?初始化?*/
renderWithHotReload(getRouter())
/*?熱更新?*/
if?(module.hot)?{
??module.hot.accept('./router/router',?()?=>?{
????const?getRouter?=?require('./router/router').default
????renderWithHotReload(getRouter())
??})
}
function?renderWithHotReload?(RootElement)?{
??ReactDom.render(
????<AppContainer>
??????{RootElement}
????</AppContainer>,
????document.getElementById('app')
??)
}
執行npm start,修改頁面的時候,state不更新
10?文件路徑優化
修改webpack.dev.config.js
resolve:?{
????alias:?{
??????pages:?path.join(__dirname,?'src/pages'),
??????components:?path.join(__dirname,?'src/components'),
??????router:?path.join(__dirname,?'src/router'),
??????actions:?path.join(__dirname,?'src/redux/actions'),
??????reducers:?path.join(__dirname,?'src/redux/reducers')
????}
??}
修改后,引用路徑就可以這樣子了
import?Home?from?'pages/Home/Home'
import?Page1?from?'pages/Page1/Page1'
11?redux
因為太多了,這邊簡單列一個例子叭
// src/redux/actions/counter.js
export?const?INCREMENT?=?'counter/INCREMENT'
export?const?DECREMENT?=?'counter/DECREMENT'
export?const?RESET?=?'counter/RESET'
export?function?increment?()?{
??return?{?type:?INCREMENT?}
}
export?function?decrement?()?{
??return?{?type:?DECREMENT?}
}
export?function?reset?()?{
??return?{?type:?RESET?}
}
// src/redux/reducers/counter.js
import?{?INCREMENT,?DECREMENT,?RESET?}?from?'../actions/counter'
/*
*?初始化state
?*/
const?initState?=?{
??count:?0
}
/*
*?reducer
?*/
export?default?function?reducer?(state?=?initState,?action)?{
??switch?(action.type)?{
????case?INCREMENT:
??????return?{
????????count:?state.count?+?1
??????}
????case?DECREMENT:
??????return?{
????????count:?state.count?-?1
??????}
????case?RESET:
??????return?{?count:?0?}
????default:
??????return?state
??}
}
// src/redux/reducers.js?
import?{?combineReducers?}?from?'redux'
import?counter?from?'reducers/counter'
export?default?combineReducers({
??counter
})
// src/redux/store.js?
import?{?createStore?}?from?'redux'import?combineReducers?from?'./reducers'
let?store?=?createStore(combineReducers)
if?(module.hot)?{
??module.hot.accept('./reducers',?()?=>?{
????const?nextCombineReducers?=?require('./reducers').default
????store.replaceReducer(nextCombineReducers)
??})
}
export?default?store
在組件中引用redux,react-redux提供了一個方法connect,connect接收兩個參數,mapStateToProps,就是把redux的state,轉為組件的Props,mapDispatchToprops, 就是把發射actions的方法,轉為Props屬性函數。
cnpm install --save?react-redux
創建src/pages/Counter/Counter.js,并在路由文件添加路由
import?React,?{?Component?}?from?'react'
import?{?increment,?decrement,?reset?}?from?'actions/counter'
import?{?connect?}?from?'react-redux'
class?Counter?extends?Component?{
??render?()?{
????return?(
??????<div>
????????<div>當前計數為{this.props.counter.count}</div>
????????<button?onClick={()?=>?this.props.increment()}>自增
????????</button>
????????<button?onClick={()?=>?this.props.decrement()}>自減
????????</button>
????????<button?onClick={()?=>?this.props.reset()}>重置
????????</button>
??????</div>
????)
??}
}
const?mapStateToProps?=?(state)?=>?{
??return?{
????counter:?state.counter
??}
}
const?mapDispatchToProps?=?(dispatch)?=>?{
??return?{
????increment:?()?=>?{
??????dispatch(increment())
????},
????decrement:?()?=>?{
??????dispatch(decrement())
????},
????reset:?()?=>?{
??????dispatch(reset())
????}
??}
}
export?default?connect(mapStateToProps,?mapDispatchToProps)(Counter)
在入口文件傳入store
import?React?from?'react'
import?ReactDom?from?'react-dom'
import?{?AppContainer?}?from?'react-hot-loader'
import?{?Provider?}?from?'react-redux'
import?store?from?'./redux/store'
import?getRouter?from?'router/router'
/*?初始化?*/
renderWithHotReload(getRouter())
/*?熱更新?*/
if?(module.hot)?{
??module.hot.accept('./router/router',?()?=>?{
????const?getRouter?=?require('router/router').default
????renderWithHotReload(getRouter())
??})
}
function?renderWithHotReload?(RootElement)?{
??ReactDom.render(
????<AppContainer>
??????<Provider?store={store}>
????????{RootElement}
??????</Provider>
????</AppContainer>,
????document.getElementById('app')
??)
}
執行npm start,打開localhost:8080/counter
12?devtool優化
增加webpack配置devtool!可以查看瀏覽器報錯的詳細代碼位置
src/webpack.dev.config.js增加devtool: ‘inline-source-map’
13? 編譯css
cnpm install css-loader style-loader --save-dev
css-loader使你能夠使用類似@import 和 url(…)的方法實現 require()的功能;
style-loader將所有的計算后的樣式加入頁面中; 二者組合在一起使你能夠把樣式表嵌入webpack打包后的JS文件中。
測試查看page1頁面效果
14?編譯圖片
cnpm install --save-dev url-loader file-loader
webpack.dev.config.js rules增加
{
????????test:?/\.(png|jpg|gif)$/,
????????use:?[{
??????????loader:?'url-loader',
??????????options:?{
????????????limit:?8192
??????????}
????????}]
??????},
options limit 8192意思是,小于等于8K的圖片會被轉成base64編碼,直接插入HTML中,減少HTTP請求。
引用圖片,查看效果
15?按需加載
打包完后,所有頁面只生成了一個build.js,當我們首屏加載的時候,就會很慢。因為也下載了別的頁面的js。
如果每個頁面都打包了自己單獨的JS,在進入自己頁面的時候才加載對應的js,那首屏加載就會快很多。
cnpm install bundle-loader --save-dev
創建src/router/Bundle.js
import?React,?{
??Component
}?from?'react'
class?Bundle?extends?Component?{
??state?=?{
????//?short?for?"module"?but?that's?a?keyword?in?js,?so?"mod"
????mod:?null
??};
??UNSAFE_componentWillMount()?{
????this.load(this.props)
??}
??UNSAFE_componentWillReceiveProps(nextProps)?{
????if?(nextProps.load?!==?this.props.load)?{
??????this.load(nextProps)
????}
??}
??load(props)?{
????this.setState({
??????mod:?null
????});
????props.load((mod)?=>?{
??????this.setState({
????????//?handle?both?es?imports?and?cjs
????????mod:?mod.default???mod.default?:?mod
??????})
????})
??}
??render()?{
????return?this.props.children(this.state.mod)
??}
}
export?default?Bundle;
修改路由文件src/router/router.js
import?React?from?'react'
import?{?Route,?Switch?}?from?'react-router-dom'
import?Bundle?from?'./Bundle'
import?Home?from?'bundle-loader?lazy&name=home!pages/Home/Home'
import?Page1?from?'bundle-loader?lazy&name=page1!pages/Page1/Page1'
import?Counter?from?'bundle-loader?lazy&name=counter!pages/Counter/Counter'
import?Loading?from?'components/Loading/Loading'
const?createComponent?=?(component)?=>?(props)?=>?(
??<Bundle?load={component}>
????{
??????(Component)?=>?Component???<Component?{...props}?/>?:?<Loading?/>
????}
??</Bundle>
)
const?getRouter?=?()?=>?(
??<div?className='margin'>
????<Switch>
??????<Route?exact?path='/'?component={createComponent(Home)}?/>
??????<Route?path='/page1'?component={createComponent(Page1)}?/>
??????<Route?path='/counter'?component={createComponent(Counter)}?/>
????</Switch>
??</div>
)
export?default?getRouter
npm run?start,打開瀏覽器,進入新的頁面,都會加載自己的JS,但是名字都是0.bundle.js,分不清哪個頁面的js,所以修改配置文件
output:?{
????path:?path.join(__dirname,?'./dist'),
????filename:?'[name].[chunkhash].js',
????chunkFilename:?'[name].[chunkhash].js',
????publicPath:?'/'
??},
運行發現名字變成home.js(router.js里面import Home from ‘bundle-loader?lazy&name=home!pages/Home/Home’;這里name=home)
16?緩存
為了讓用戶第二次訪不重復下載js,所以要做個緩存,但緩存后,我們修改代碼,更新線上后,用戶還是之前的js,那就會出bug
所以代碼更新后,最好使打包生成的名字不一樣。比如第一次叫home.a.js,第二次叫home.b.js。
修改配置文件
output:?{
??path:?path.join(__dirname,?'./dist'),
??filename:?'[name].[hash].js',
??chunkFilename:?'[name].[chunkhash].js'
}
打包都用增加hash,修改了文件,打包后相應的文件名字也改變了
17?HtmlWebpackPlugin
這個插件,每次會自動把js插入到你的模板index.html里面
cnpm install html-webpack-plugin --save-dev
新建模板src/index.html
<!DOCTYPE?html>
<html?lang="en">
<head>
??<meta?charset="UTF-8">
??<meta?name="viewport"?content="width=device-width,?initial-scale=1.0">
??<title>test2</title>
</head>
<body>
??<div?id="app"></div>
</body>
</html>
修改webpack.dev.config.js,增加plugin
new?HtmlWebpackPlugin({
??????filename:?'index.html',
??????template:?path.join(__dirname,?'src/index.html')
????}),
18?提取公共代碼
打包后bundle.js里面包含了react,redux,react-router等等公共庫,這些代碼基本上不會改變的。但是,他們合并在bundle.js里面,每次項目發布,重新請求bundle.js的時候,相當于重新請求了react等這些公共庫所以把react這些不會改變的公共庫提取出來,用戶緩存下來。從此以后,用戶再也不用下載這些庫了
const?webpack?=?require('webpack')
entry:?{
????app:?[
??????path.join(__dirname,?'src/index.js')
????],
????vendor:?['react',?'react-router-dom',?'redux',?'react-dom',?'react-redux']
??},
// plugins
new?webpack.optimize.CommonsChunkPlugin({
??????name:?'vendor'
????}),
把react等庫生成打包到vendor.hash.js里面去。
但是發現編譯生成的文件app.[hash].js和vendor.[hash].js生成的hash一樣的,因為每次修改代碼,都會導致vendor.[hash].js名字改變,那我們提取出來的意義也就沒了。其實文檔上寫的很清楚
output:?{
??path:?path.join(__dirname,?'./dist'),
??filename:?'[name].[hash].js',?//這里應該用chunkhash替換hash
??chunkFilename:?'[name].[chunkhash].js'
}
但是如果用chunkhash,會報錯。和webpack-dev-server –hot不兼容,
所以配置正式版webpack.config.js
新建webpack.config.js
先刪除webpack-dev-server相關的東西
devtool的值改成cheap-module-source-map
hash改成chunkhash
const?path?=?require('path')
var?HtmlWebpackPlugin?=?require('html-webpack-plugin')
var?webpack?=?require('webpack')
module.exports?=?{
??devtool:?'cheap-module-source-map',
??entry:?{
????app:?[
??????path.join(__dirname,?'src/index.js')
????],
????vendor:?['react',?'react-router-dom',?'redux',?'react-dom',?'react-redux']
??},
??output:?{
????path:?path.join(__dirname,?'./dist'),
????filename:?'[name].[chunkhash].js',
????chunkFilename:?'[name].[chunkhash].js'
??},
??module:?{
????rules:?[{
??????test:?/\.js$/,
??????use:?['babel-loader'],
??????include:?path.join(__dirname,?'src')
????},?{
??????test:?/\.css$/,
??????use:?['style-loader',?'css-loader']
????},?{
??????test:?/\.(png|jpg|gif)$/,
??????use:?[{
????????loader:?'url-loader',
????????options:?{
??????????limit:?8192
????????}
??????}]
????}]
??},
??plugins:?[
????new?HtmlWebpackPlugin({
??????filename:?'index.html',
??????template:?path.join(__dirname,?'src/index.html')
????}),
????new?webpack.optimize.CommonsChunkPlugin({
??????name:?'vendor'
????})
??],
??resolve:?{
????alias:?{
??????pages:?path.join(__dirname,?'src/pages'),
??????component:?path.join(__dirname,?'src/component'),
??????router:?path.join(__dirname,?'src/router'),
??????actions:?path.join(__dirname,?'src/redux/actions'),
??????reducers:?path.join(__dirname,?'src/redux/reducers')
????}
??}
}
在package.json增加打包腳本
"build":?"webpack?--config?webpack.config.js"
執行npm run build~看看dist文件夾
19?文件壓縮
cnpm i --save-dev uglifyjs-webpack-plugin
修改配置文件
var?UglifyJSPlugin?=?require('uglifyjs-webpack-plugin')
//?plugins
new?UglifyJSPlugin(),
npm run build發現打包文件大小減小了好多
20?指定環境
許多 library 將通過與 process.env.NODE_ENV 環境變量關聯,以決定 library 中應該引用哪些內容。例如,當不處于生產環境中時,某些 library 為了使調試變得容易,可能會添加額外的日志記錄(log)和測試(test)。其實,當使用 process.env.NODE_ENV === ‘production’ 時,一些 library 可能針對具體用戶的環境進行代碼優化,從而刪除或添加一些重要代碼。我們可以使用 webpack 內置的 DefinePlugin 為所有的依賴定義這個變量:
//?plugins
new?webpack.DefinePlugin({??????'process.env':?{
????????'NODE_ENV':?JSON.stringify('production')
??????}
????}),
npm run build后發現vendor.[hash].js又變小了。
21?優化緩存
剛才我們把[name].[hash].js變成[name].[chunkhash].js后,npm run build后,發現app.xxx.js和vendor.xxx.js不一樣。
隨便修改代碼一處,例如Home.js,隨便改變個字,你發現home.xxx.js名字變化的同時,vendor.xxx.js名字也變了。這不行啊。這和沒拆分不是一樣一樣了嗎?我們希望是vendor.xxx.js名字永久不變,一直緩存在用戶本地的。
官方文檔推薦了一個插件HashedModuleIdsPlugin
plugins:?[
??new?webpack.HashedModuleIdsPlugin(),
? new webpack.optimize.CommonsChunkPlugin({ name: 'runtime' }) //? 引入順序在這里很重要。CommonsChunkPlugin 的 ‘vendor’ 實例,必須在 ‘runtime’ 實例之前引入。
]
22?打包優化
cnpm install clean-webpack-plugin --save-dev
修改webpack.config.js
const?CleanWebpackPlugin?=?require('clean-webpack-plugin');
plugins:?[
????new?CleanWebpackPlugin(['dist'])
]
23?抽取css
cnpm install --save-dev extract-text-webpack-plugin
const?ExtractTextPlugin?=?require("extract-text-webpack-plugin");
module.exports?=?{
??module:?{
????rules:?[
??????{
????????test:?/\.css$/,
????????use:?ExtractTextPlugin.extract({
??????????fallback:?"style-loader",
??????????use:?"css-loader"
????????})
??????}
????]
??},
??plugins:?[
?????new?ExtractTextPlugin({
?????????filename:?'[name].[contenthash:5].css',
?????????allChunks:?true
?????})
??]
}
npm run build后發現單獨生成了css文件
24?合并提取webpack公共配置
把公共的配置文件提取出來。提取到webpack.common.config.js里面~
webpack.dev.config.js和webpack.config.js寫自己的特殊的配置。
這里我們需要用到webpack-merge來合并公共配置和單獨的配置。
cnpm install --save-dev webpack-merge
新建webpack.common.config.js
const?path?=?require('path');
const?HtmlWebpackPlugin?=?require('html-webpack-plugin');
const?webpack?=?require('webpack');
commonConfig?=?{
????entry:?{
????????app:?[
????????????path.join(__dirname,?'src/index.js')
????????],
????????vendor:?['react',?'react-router-dom',?'redux',?'react-dom',?'react-redux']
????},
????output:?{
????????path:?path.join(__dirname,?'./dist'),
????????filename:?'[name].[chunkhash].js',
????????chunkFilename:?'[name].[chunkhash].js',
????????publicPath:?"/"
????},
????module:?{
????????rules:?[{
????????????test:?/\.js$/,
????????????use:?['babel-loader?cacheDirectory=true'],
????????????include:?path.join(__dirname,?'src')
????????},?{
????????????test:?/\.(png|jpg|gif)$/,
????????????use:?[{
????????????????loader:?'url-loader',
????????????????options:?{
????????????????????limit:?8192
????????????????}
????????????}]
????????}]
????},
????plugins:?[
????????new?HtmlWebpackPlugin({
????????????filename:?'index.html',
????????????template:?path.join(__dirname,?'src/index.html')
????????}),
????????new?webpack.HashedModuleIdsPlugin(),
????????new?webpack.optimize.CommonsChunkPlugin({
????????????name:?'vendor'
????????}),
????????new?webpack.optimize.CommonsChunkPlugin({
????????????name:?'runtime'
????????})
????],
????resolve:?{
????????alias:?{
????????????pages:?path.join(__dirname,?'src/pages'),
????????????components:?path.join(__dirname,?'src/components'),
????????????router:?path.join(__dirname,?'src/router'),
????????????actions:?path.join(__dirname,?'src/redux/actions'),
????????????reducers:?path.join(__dirname,?'src/redux/reducers')
????????}
????}
};
module.exports?=?commonConfig;
修改?webpack.dev.config.js
const?merge?=?require('webpack-merge');
const?path?=?require('path');
const?commonConfig?=?require('./webpack.common.config.js');
const?devConfig?=?{
????devtool:?'inline-source-map',
????entry:?{
????????app:?[
????????????'react-hot-loader/patch',
????????????path.join(__dirname,?'src/index.js')
????????]
????},
????output:?{
????????/*這里本來應該是[chunkhash]的,但是由于[chunkhash]和react-hot-loader不兼容。只能妥協*/
????????filename:?'[name].[hash].js'
????},
????module:?{
????????rules:?[{
????????????test:?/\.css$/,
????????????use:?["style-loader",?"css-loader"]
????????}]
????},
????devServer:?{
????????contentBase:?path.join(__dirname,?'./dist'),
????????historyApiFallback:?true,
????????host:?'0.0.0.0',
????}
};
module.exports?=?merge({
????customizeArray(a,?b,?key)?{
????????/*entry.app不合并,全替換*/
????????if?(key?===?'entry.app')?{
????????????return?b;
????????}
????????return?undefined;
????}
})(commonConfig,?devConfig);
修改webpack.config.js
const?merge?=?require('webpack-merge');
const?webpack?=?require('webpack');
const?UglifyJSPlugin?=?require('uglifyjs-webpack-plugin');
const?CleanWebpackPlugin?=?require('clean-webpack-plugin');
const?ExtractTextPlugin?=?require("extract-text-webpack-plugin");
const?commonConfig?=?require('./webpack.common.config.js');
const?publicConfig?=?{
????devtool:?'cheap-module-source-map',
????module:?{
????????rules:?[{
????????????test:?/\.css$/,
????????????use:?ExtractTextPlugin.extract({
????????????????fallback:?"style-loader",
????????????????use:?"css-loader"
????????????})
????????}]
????},
????plugins:?[
????????new?CleanWebpackPlugin(['dist/*.*']),
????????new?UglifyJSPlugin(),
????????new?webpack.DefinePlugin({
????????????'process.env':?{
????????????????'NODE_ENV':?JSON.stringify('production')
????????????}
????????}),
????????new?ExtractTextPlugin({
????????????filename:?'[name].[contenthash:5].css',
????????????allChunks:?true
????????})
????]
};
module.exports?=?merge(commonConfig,?publicConfig);
25?優化目錄結構并增加404頁面
優化下目錄結構,把router和nav分開,新建根組件App
新建根組件components/App/APP.js
import?React,?{Component}?from?'react';
import?Nav?from?'components/Nav/Nav';
import?getRouter?from?'router/router';
export?default?class?App?extends?Component?{
????render()?{
????????return?(
????????????<div>
????????????????<Nav/>
????????????????{getRouter()}
????????????</div>
????????)
????}
}
新建components/Nav/Nav組件,把router/router.js里面的nav提出來。
新建components/Loading/Loading組件,把router/router.js里面的Loading提出來。
入口文件src/index.js修改
import?React?from?'react';
import?ReactDom?from?'react-dom';
import?{AppContainer}?from?'react-hot-loader';
import?{Provider}?from?'react-redux';
import?store?from?'./redux/store';
import?{BrowserRouter?as?Router}?from?'react-router-dom';
import?App?from?'components/App/App';
renderWithHotReload(App);
if?(module.hot)?{
????module.hot.accept('components/App/App',?()?=>?{
????????const?NextApp?=?require('components/App/App').default;
????????renderWithHotReload(NextApp);
????});
}
function?renderWithHotReload(RootElement)?{
????ReactDom.render(
????????<AppContainer>
????????????<Provider?store={store}>
????????????????<Router>
????????????????????<RootElement/>
????????????????</Router>
????????????</Provider>
????????</AppContainer>,
????????document.getElementById('app')
????)
}
新建pages/NotFound/NotFound組件。
修改router/router.js,增加404
import?NotFound?from?'bundle-loader?lazy&name=notFound!pages/NotFound/NotFound';
<Route?component={createComponent(NotFound)}/>
26?集成PostCSS
npm install --save-dev postcss-loader
npm install --save-dev postcss-cssnext //??postcss-cssnext允許你使用未來的 CSS 特性(包括 autoprefixer)
修改webpack配置文件,增加postcss-loader
修改webpack.config.js
rules:?[{
??test:?/\.css$/,
??use:?ExtractTextPlugin.extract({
??????fallback:?"style-loader",
??????use:?["css-loader",?"postcss-loader"]
??})
}]
修改webpack.dev.config.js
rules:?[{
??test:?/\.(css|scss)$/,
??use:?["style-loader",?"css-loader",?"postcss-loader"]
}]
根目錄增加postcss配置文件。
module.exports?=?{
??plugins:?{
????'postcss-cssnext':?{}
??}
}
先這些叭沒有了