webpack3.x+react+react-redux完整实例搭建过程

2 篇文章 0 订阅
2 篇文章 0 订阅

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

<!DOCTYPE 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 demo</title>
</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>
    )
  }
}

store文件夹

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 的方法就是触发 actionaction 是一个用于描述已发生事件的普通对象。'},
        {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 自己随便找一个


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值