react-webpack2-完整案例

react-webpack 2 - 完整配置案例

源码

webpack 开发跨域问题解决
react16 + react-router4 + webpack开发环境搭建

1.先定义一些配置常量 /webpack/config.js

    // 引入 node.js path 模块
    const path = require('path');

    // sass-loader 的 配置
    exports.sassLoaderConfig = '?outputStyle=expanded';

    // 公共文件
    exports.vendor = [
        'react',
        'react-dom',
        'react-redux',
        'react-router',
        'react-router-redux',
        'redux',
        'redux-thunk'
    ];

    // css 代码自动补全配置
    exports.autoConfig = {
        browsers: [
            'ie >= 9',
            'ie_mob >= 10',
            'ff >= 30',
            'chrome >= 34',
            'safari >= 7',
            'opera >= 23',
            'ios >= 7',
            'android >= 4.4',
            'bb >= 10'
        ],
        cascade: true,
        remove: true
    };

    // js 压缩 配置
    exports.uglifyJsConfig = {
        beautify: false,    // 不美化输出
        compress: {
            warnings: false, // 不保留警告
            drop_debugger: true, // 不保留调试语句
            drop_console: true // 不保留控制台输出信息
        },
        mangle: {           // 跳过这些,不改变命名
            except: ['$super', '$', 'exports', 'require']
        },
        space_colon: false,
        comments: false     // 不保留注释
    };

    // 定义 文件路径 注:文件在 根目录下的 webpack 文件夹下
    const ROOT_PATH = path.resolve(__dirname, '../');
    exports.defPath = {
        ROOT_PATH: ROOT_PATH,
        APP_PATH: path.resolve(ROOT_PATH, 'app'),
        DEV_PATH: path.resolve(ROOT_PATH, 'dev'),
        BUILD_PATH: path.resolve(ROOT_PATH, 'build'),
        TPL_PATH: path.resolve(ROOT_PATH, 'app/tpl.html'),
        ENTRY_PATH: path.resolve(ROOT_PATH, 'app/js/index.js'),
        ESLINT_PATH: path.resolve(ROOT_PATH, './.eslintrc'),
        REQUEST_PATH: path.resolve(ROOT_PATH, 'app/js/utils/request')
    }

2.定义不同环境变量下的 应用请求配置

    // `npm install ip` 获取本机 ip 用于配置服务器
    const ip = require('ip').address();

    module.exports = {
        test: 'http://xxx.xxx',
        development: 'http://' + ip + ':3003',
        production: 'http://xxx.xxx'
    };

定义公共的配置 /webpack/base.js


    const webpack = require('webpack');
    const autoprefixer = require('autoprefixer');
    const HtmlWebpackPlugin = require('html-webpack-plugin');

    const config = require('./config'); // 引入配置
    const API = require('./API');
    const defPath = config.defPath;
    const APP_PATH = defPath.APP_PATH; // 源码目录

    module.exports = function () {
       return {
          context: defPath.ROOT_PATH, // 设置跟目录为执行环境
          resolve: {        // 解析模块请求的选项
             modules: [         
                APP_PATH,
                'node_modules'
             ],
             // 用于查找模块的目录
             extensions: [
                '.js', '.json', '.jsx', '.css'
            ]
            // 使用的扩展名
          },
          cache: true,  // 启用缓存
          module: {     // 公用的加载器
             rules: [
                {
                   enforce: 'pre',  // 前置执行
                    test : /\.(js|jsx)$/,
                   include : APP_PATH,
                   loader : 'eslint-loader',
                   options: {
                      configFile: defPath.ESLINT_PATH   // 指定 eslint 的配置文件路径
                   }
                },
                {
                   test: /\.(js|jsx)$/,
                    include: APP_PATH,
                    loader: 'babel-loader'
                },
                {   // 向应用特定文件中注入变量,应用中可以直接使用 baseUrl
                   test: require.resolve(defPath.REQUEST_PATH),
                   loader: 'imports-loader?baseUrl=>'+ JSON.stringify( API[ process.env.NODE_ENV || 'development' ] )
                }
             ]
          },
          plugins: [
            // autoprefixer 是 postcss-loader 的 插件,需要在这里进行 autoprefixer 插件的配置
             new webpack.LoaderOptionsPlugin({
                options: {
                   context: '/',
                   minimize: true,
                   postcss: [autoprefixer(config.autoConfig)]
                }
             }),
             // 依照模板生成 html
             new HtmlWebpackPlugin({
                template: defPath.TPL_PATH,
                title: 'Hello World app',
                filename: 'index.html',
                inject: 'body',
                minify: {
                    removeComments: true
                },
                cache: false
            })
          ]
       }
    }

开发环境的 webpack 配置 /webpack.dev.config.js

    const webpackMerge = require('webpack-merge');
    const webpack = require('webpack');
    const ChunkManifestPlugin = require('chunk-manifest-webpack-plugin');
    const ip = require('ip').address();

    const baseConfig = require('./webpack/base');
    const config = require('./webpack/config');
    const defPath = config.defPath;
    const APP_PATH = defPath.APP_PATH;

    // 使用 `webpack-merge` 将基础配置和新配置合并
    module.exports = webpackMerge(baseConfig(), {
        devtool: 'cheap-module-source-map', // 增强浏览器调试
        entry: {    // 入口
            app: [  // 热加载配置
                'react-hot-loader/patch',
                'webpack-dev-server/client?http://' + ip + ':8090',
                'webpack/hot/only-dev-server',
                './app/js/index.js'
            ],
            vendor: config.vendor   // 公共文件单独打包
        },
        output: {   // 出口
            path: defPath.DEV_PATH,     // 所有输出文件的目标路径
            // 所有输出文件的目标路径
            filename: 'js/bundle.js',   // 输出文件命名
            publicPath: '/',        // 必须写,且与 devServer 的 publicPath 保持一致
            chunkFilename: '[name].chunk.js'  // 分块文件命名
        },
        module: {
            rules: [    // 配置加载器
                {
                    test: /\.(scss|sass|css)$/,
                    include: APP_PATH,  //  必须匹配选项
                    use: [      // 2.x 版本改为 use 代替 loaders,必须加 -loader
                        'style-loader', 'css-loader', 'postcss-loader', 'sass-loader' + config.sassLoaderConfig
                    ]
                }, {
                    test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif|mp4|webm)(\?\S*)?$/,
                    include: APP_PATH,
                    loader: 'url-loader?limit=8192&name=imgs/[name].[ext]'
                }
            ]
        },
        plugins: [
            // 热模块替换相关插件
            new webpack.HotModuleReplacementPlugin(),
            new webpack.NamedModulesPlugin(),
            // 定义环境变量
            new webpack.DefinePlugin({
                'process.env.NODE_ENV': JSON.stringify('development')
            }),
            /* 
                公用模块单独打包,对应 入口文件 vendor,
                持久化缓存配置 
            */
            new webpack.optimize.CommonsChunkPlugin({
                names: [    // 提取公共模块名称
                    'vendor', 'manifest' // manifest 用于分离 webpack runtime 
                ],
                filename: 'js/[name].js', // 公共模块文件名
                minChunks: Infinity     // Infinity 表示仅仅创建公共组件块,不会把任何modules打包进去。
            }),
            new ChunkManifestPlugin({   // 将 manifest 提取到一个单独的 JSON 文件中
             filename: 'chunk-manifest.json',
             manifestVariable: 'webpackManifest' // 全局变量的名称,webpack 将利用它查找 manifest JSON 对象
          })
        ],
        devServer: {    // 开启服务器
            contentBase: defPath.DEV_PATH,
            publicPath: '/',
            historyApiFallback: true,
            clientLogLevel: 'none',
            host: ip,
            port: 8090,
            open: true,
            hot: true,
            inline: true,
            compress: true,
            stats: {
                colors: true,
                errors: true,
                warnings: true,
                modules: false,
                chunks: false
            }
        }
    })

生产环境 webpack 配置 /webpack.prod.config.js

    const webpackMerge = require('webpack-merge');
    const webpack = require('webpack');
    const ChunkManifestPlugin = require('chunk-manifest-webpack-plugin');
    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    const WebpackMd5Hash = require('webpack-md5-hash');

    const baseConfig = require('./webpack/base');
    const config = require('./webpack/config');
    const defPath = config.defPath;
    const APP_PATH = defPath.APP_PATH;

    module.exports = webpackMerge(baseConfig(), {
        entry: {
            app: defPath.ENTRY_PATH,
            vendor: config.vendor
        },
        output: {
            path: defPath.BUILD_PATH,
            // 所有输出文件的目标路径
            filename: 'js/bundle.js?[chunkhash]',
            publicPath: 'http://xxx.xxx',   // 修改成发布的地址
            chunkFilename: 'chunk.js?[chunkhash]'
        },
        module: {
            rules: [
                {
                    test: /\.(scss|sass|css)$/,
                    include: APP_PATH,
                    use: ExtractTextPlugin.extract({    // css 单独打包,(2.x 改变很大)
                        fallback: 'style-loader',
                        use: 'css-loader!postcss-loader!sass-loader' + config.sassLoaderConfig
                    })
                }, {
                    test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif|mp4|webm)(\?\S*)?$/,
                    include: APP_PATH,
                    loader: 'url-loader?limit=8192&name=imgs/[name].[ext]?[hash]'
                }
            ]
        },
        plugins: [
            new WebpackMd5Hash(),   // 取代标准webpack chunkhash
            new webpack.DefinePlugin({
                'process.env.NODE_ENV': JSON.stringify('production')
            }),

            // js 压缩
            new webpack.optimize.UglifyJsPlugin(config.uglifyJsConfig),
            new webpack.optimize.CommonsChunkPlugin({
                names: [
                    'vendor', 'manifest'
                ],
                filename: 'js/[name].js?[chunkhash]',
                minChunks: Infinity
            }),
            new ChunkManifestPlugin({
                filename: 'chunk-manifest.json',
                manifestVariable: 'webpackManifest'
            }),
            // css 抽取
            new ExtractTextPlugin({
                filename: 'css/styles.css?[contenthash]',
                disable: false,
                allChunks: true
            })
        ]
    })

对应的 babel 配置 /.babelrc

    {
        "presets": [
            ["es2015", {
                "modules": false
            }],
            "stage-2",
            "react"
        ],
        "plugins": [
            "react-hot-loader/babel",
            "transform-object-assign",
            "transform-decorators-legacy"
        ],
        "env": {
            "development": {
                "plugins": [
                    "react-hot-loader/babel"
                ]
            }
        }
    }

重要插件版本列表


{
    "webpack": "^2.2.1",
    "webpack-dev-server": "^2.4.1",
    "webpack-md5-hash": "0.0.5",
    "webpack-merge": "^4.0.0",
    "chunk-manifest-webpack-plugin": "^1.0.0",
    "extract-text-webpack-plugin": "^2.1.0",
    "html-webpack-plugin": "^2.28.0",
    "react-hot-loader": "^3.0.0-beta.6",
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值