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': {}
}
}
先这些叭没有了