1.本次搭建过程起初想升级到最新的webpack4.x 发现在extract-text-webpack-plugin 样式打包组件有比较多的问题改成了webpack3.x,于以前老的还是区别很大
安装:cnpm install --save-dev webpack
cnpm install --save-dev webpack-dev-server
在配置过程需要一些组件和工具:cnpm install --save-dev style-loader css-loader less less-loader url-loader file-loader img-loader 这些是对css img less 的处理需要用到的依赖包
对打包后的css 添加前缀: cnpm install --save-dev postcss-loader autoprefixer autoprefixer-loader
每次重新打包清理对应打包的文件插件: cnpm install --save-dev clean-webpack-plugin
因为这次是react 自然少不了 react js解析有关的:
cnpm install --save-dev babel babel-cli babel-core babel-loader babel-preset-es2015
然后跟react 自身有关的:
cnpm install --save-dev react react-dom react-router react-router-dom redux redux-logger babel-runtime babel-preset-react
ui框架用的是antd
框架安装:cnpm install --save-dev antd-mobile
按需加载js:cnpm install --save-dev babel-plugin-syntax-dynamic-import
需要的安装依赖基本完毕。。。。。开始操刀
项目结构:
webpack 配置代码奉上:
/* * Created with wxl. * Date: 2018/2/28 * Time: 16:33 * */ const webpack = require('webpack'); const path = require('path'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); //css单独打包 const HtmlWebpackPlugin = require('html-webpack-plugin');//自动生成 index.html const CleanWebpackPlugin = require('clean-webpack-plugin');//清理 dist module.exports = { entry : { main : path.resolve(__dirname,'./src/index.js'), }, output:{ path:path.resolve(__dirname,'./dist/'), filename: 'js/bundle.js' }, devtool: 'eval-source-map', module: { rules: [ {test: /\.css$/, exclude:/^node_modules$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use:[ { loader: 'css-loader', options: {sourceMap: true,importLoaders: 1 } }, 'postcss-loader', ] }) }, {test: /\.less$/, exclude: /node_modules/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: [ { loader: 'css-loader', options: {sourceMap: true,importLoaders: 1 }}, 'postcss-loader', {loader: 'less-loader'}, ] }) }, {test:/\.(png|jpg|gif|svg)(\?.*)?$/, exclude: /node_modules/, use: [ { //加载url-loader; loader : 'url-loader', options : { //20000,当然css文件体积更大; limit : 20000, outputPath:'images/', publicPath: '../images/', name: '[name].[hash:7].[ext]' } }, { //压缩图片(另一个压缩图片:image-webpack-loader); loader : 'img-loader?minimize&optimizationLevel=5&progressive=true' }, ] }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, exclude: /node_modules/, use: [ { //加载url-loader ; loader : 'file-loader', options : { limit: 20000, outputPath:'media/', name: '[name].[hash:7].[ext]' } } ] }, { test: /\.(eot|woff|svg|ttf|woff2|gif|appcache)(\?|$)/, exclude: /node_modules/, use: [ { //加载file-loader ; loader : 'file-loader', options : { limit: 20000, outputPath:'fonts/', //设置字体; name:'[name].[hash:7].[ext]' } } ] }, {test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'], compact: 'false', plugins: ['syntax-dynamic-import']//按需加载配置 } } } ] }, plugins:[ new ExtractTextPlugin({filename:'style/[name].css'}), new webpack.optimize.ModuleConcatenationPlugin(), new webpack.HotModuleReplacementPlugin(), new CleanWebpackPlugin(['dist']), new HtmlWebpackPlugin({ //根据模板插入css/js等生成最终HTML title:"demo", filename: '/index.html', //生成的html存放路径,相对于 path template:path.join(__dirname,'src/index.html'), //html模板路径 hash: true, //为静态资源生成hash值 }), ], resolve: { extensions: [ '.js', '.json','.less','jsonp'],//后缀名自动补全 }, devServer:{ contentBase: path.join(__dirname, 'dev'), //设置启动文件目录; inline:true,//开启更新客户端入口(可在package.json scripts 里设置 npm run xxx); hot: true,//设置热更新(可在package.json scripts 里设置 npm run xxx); port:3000,//设置端口号; /* open:true //自动拉起浏览器*/ } };
需要注意的地方extract-text-webpack-plugin打包后的css 或者less 里面的backgroud-img 路径会出现错误
加一个 publicPath: '../images/',这样就引用打包后的图片不会报错
package.json 需要的组件依赖版本奉上,里面scripts需要配置根据个人需要添加相应的配置
{ "name": "react", "version": "0.0.1", "description": "", "dependencies": { "antd-mobile": "^2.1.6", "babel-runtime": "^6.23.0", "react": "^16.3.2", "react-dom": "^16.3.2", "react-router": "^3.0.2" }, "devDependencies": { "antd-mobile": "^2.1.8", "autoprefixer": "^8.3.0", "autoprefixer-loader": "^3.2.0", "axios": "^0.16.2", "babel": "^6.23.0", "babel-cli": "^6.24.1", "babel-core": "^6.25.0", "babel-loader": "^7.1.1", "babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-preset-es2015": "^6.24.1", "babel-preset-es2016": "^6.24.1", "babel-preset-react": "^6.24.1", "clean-webpack-plugin": "^0.1.19", "css-loader": "^0.28.11", "extract-text-webpack-plugin": "^3.0.2", "file-loader": "^1.1.11", "html-webpack-plugin": "^2.29.0", "img-loader": "^2.0.1", "less": "^3.0.2", "less-loader": "^4.1.0", "normalize.css": "^8.0.0", "postcss-loader": "^2.0.5", "react-hot-loader": "^1.3.1", "react-redux": "^5.0.7", "react-router-dom": "^4.2.2", "react-router-redux": "^4.0.8", "redux": "^4.0.0", "redux-logger": "^3.0.6", "style-loader": "^0.18.2", "url-loader": "^0.5.9", "webpack": "^3.11.0", "webpack-dev-server": "^1.16.5" }, "scripts": { "dev": "webpack-dev-server --devtool eval --progress --colors --hotOnly --inline --content-base dev", "build": "webpack --watch --progress --display-modules --colors --display-reasons" }, "author": "wxl", "license": "ISC" }
index.js 代码奉上
/* * Created with wxl. * Date: 2018/4/27 * Time: 14:56 * */ import './assets/style/index.less'; import 'normalize.css'; //重置浏览器默认样式 import React, { Component } from 'react'; import ReactDOM, { render } from 'react-dom'; import { Provider } from 'react-redux'; import Container from './router/router'; import finalCreateStore from './store/configureStore' //引入store配置 import reducer from './reducers' // 引入reducers集合 import 'antd-mobile/dist/antd-mobile.css';//全局引入antd-mobile.css样式 // 给增强后的store传入reducer const store = finalCreateStore(reducer) ReactDOM.render(<div className="app-wrapper"><Provider store={store}><Container/>Provider>div>, document.getElementById('app'));
新建一个模板index.html
html>
<html lang="en">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<head>
<meta charset="UTF-8">
<title>react demotitle>
head>
<body>
<div id="app">div>
body>
html>
router 文件夹router.js 路由组件Container,代码奉上:
/* * Created with wxl. * Date: 2018/4/27 * Time: 14:57 * */ import React, {Component} from 'react'; import { BrowserRouter ,hashHistory ,Route, Redirect, Link, Switch ,withRouter ,matchPath } from 'react-router-dom'; import Login from '../components/views/login'; export default class Container extends Component{ constructor(props){ super(props); } render(){ return( <div className='app-content'> <BrowserRouter history={hashHistory}> <Route path="/" component={Login}/> BrowserRouter> div> ) } }
configureStore.js 代码奉上:
import {createLogger} from 'redux-logger' // redux-logger支持 createLogger import { createStore, applyMiddleware, compose } from 'redux' // 引入redux createStore、中间件及compose // 创建一个中间件集合 const logger = createLogger(); // 利用compose增强store,这个 store 与 applyMiddleware const finalCreateStore = compose( applyMiddleware(logger), )(createStore) export default
reducers 文件夹
index.js
// reducers/index.js import { combineReducers } from 'redux' // 利用combineReducers 合并reducers import { routerReducer } from 'react-router-redux' // 将routerReducer一起合并管理 import update from './count' // 引入update这个reducer export default combineReducers({ update, routing: routerReducer })
count.js 数据:
const INCREASE='INCREASE'; const DECREASE='DECREASE'; const GETSUCCESS='GETSUCCESS'; const REFRESHDATA='REFRESHDATA'; // 初始化state数据 const initialState = { number: 1, lists: [ {text: '整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。'}, {text: '惟一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。'}, {text: '为了描述 action 如何改变 state tree ,你需要编写 reducers。'}, {text: '就是这样,现在你应该明白 Redux 是怎么回事了。'} ], data: [] } // 通过dispatch action进入 export default function update(state = initialState, action) { // 根据不同的action type进行state的更新 switch(action.type) { case INCREASE: return Object.assign({}, state, { number: state.number + action.amount }) break case DECREASE: return Object.assign({}, state, { number: state.number - action.amount }) break case GETSUCCESS: return Object.assign({}, state, { data: action.json }) case REFRESHDATA: return Object.assign({}, state, { data: [] }) default: return state } }
配置新建文件.babelrc
{ "presets": [ "react", [ "es2015", { "modules": false } ] ] }
配置新建文件.gitignore
node_modules/ build/
配置新建文件postcss.config.js配置(postcss-loader 设置需要针对手机安卓和iso版本),代码奉上
/** * Created by wxl 2018 4 24 1630. */ module.exports = { plugins: [ require('autoprefixer')({browsers:'ios >= 8'}) ] };
最后是组件代码login.js
/* * Created with wxl. * Date: 2018/3/14 * Time: 16:54 * */ import React, {Component} from 'react'; import './login.less'; import {Flex, Button, List, InputItem, Toast } from 'antd-mobile'; import { browserHistory,History } from 'react-router'; import Book from '../books/book'; export default class Login extends Component{ constructor(props){ super(props); this.state = { logging:false, useName:'admin', psd:'12345' } } /* isEmpty(val){ return val === '' }*/ //登陆校验 loginEnter() { this.context.router.history.push({ pathname: '/book/' + res.loginname }); } componentWillMount(){ } render(){ let {useName, psd} = this.state; return( <div className='login-wrapper'> <List > <InputItem type="text" value={useName} placeholder="请输入用户名">用户名InputItem> <InputItem type="password" value={psd} placeholder="请输入密码">密码InputItem> List> <div className="login-footer"> <Flex> <Flex.Item> <Button type="primary" onClick={this.loginEnter}>登录Button>Flex.Item> <Flex.Item><Button type="primary">注册Button>Flex.Item> Flex> div> div> ) } }assets 里面的静态文件index.less和img bg.png 自己随便找一个