wepack3 详解


原文链接: wepack3 详解

webpack3中文文档
Fis3构建迁移Webpack之路
大公司里怎样开发和部署前端代码
awesome-webpack-cn
webpack进阶之插件篇
webpack飞行手册 推荐

webpack

entry:入口,定义要打包的文件
output:出口,定义打包输出的文件;包括路径,文件名,还可能有运行时的访问路径(publicPath)参数
module: webpack将所有资源都看做是模块,而模块就需要加载器;
loaders: Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。
plugins:定义以下额外的插件
resolve:定义能够被打包的文件,文件后缀名

extensions: ['', '.js', '.es6']

wenbpack 安装失败的原因

  • 1、网络问题 cnpm
  • 2、权限问题
  • 3、node 版本问题

==============================================

webpack版本问题修改

  • 新项目
    >直接删除node_modules 重新安装 npm install --save-dev webpack
  • 旧项目
    >修改package.json中的版本号 删除node_modules 重新 npm install

===============================================

学习步骤

  • 1、配置文件webpack.config.js
  • 2、entery选项(入口配置)
  • 3、output选项(出口配置)
  • 4、多入口、多出口配置

==================================================

基本结构

const path=require('path');
module.export={

entry:{
    entry:'文件路径'
},       入口配置
output:{
    path:path.resolve(__dirname,'dist'),  node语法相对路径
    filename:'[name].js'    //压缩后的文件名
},      出口配置
module:{},      解读css  图片转换压缩
plugins:[]      插件
devServer:{}    配置服务

}

======================================================

webpack配置服务、热更新技术

devServer:{

contentBase:path.resolve(__dirname,'dist'),
host:'192.168.199.106',           //服务器地址
compress:true,                    //服务器是否压缩
port:1717                        //服务器端口

}

  • npm install webpack-dev-server --save-dev
  • 修改package.json
  • "script":{
    "server":"webpack-dev-server"
    }
    >起服务 npm run server

webpack3.6以上的热更新

=========================================================

css打包

  • style-loader //处理css中URL
  • css-loader //对标签处理


module:{

    rules:[
        {
            test:/\.css$/,    //通过正则的方式找到处理的扩展
            //use:['style-loader','css-loader]
            //loader
            //use:[{
                loader:'style-loader'
                },{
                    loader:'css-loader'
            }]
        }
    ]
},

================================================================

js打包

引入插件 uglify

  • const uglify = require('uglifyjs-webpack-plugin');

  • plugins:[
    new uglify()
    ]

==================================================================

html打包

  • 安装并引入插件 html-webpack-plugin
  • const htmlPlugin = require('html-webpack-plugin');
  • plugins:[
    new htmlPlugin({

    minify:{
        removeAttributeQuotes:true
    },
    hash:true,
    template:'./src/index.html'
    

    })
    ]

  • minify:是对html文件进行压缩,removeAttrubuteQuotes是却掉属性的双引号。

  • hash:为了开发中js有缓存效果,所以加入hash,这样可以有效避免缓存JS。

  • template:是要打包的html模版路径和文件名称。

=====================================================================

css图片路径问题

  • module:[{
    rules{

    test:/\.(png|jpg|gif)/,
    use:[{
        loader:'url-loader',
        options:{
            limit:50000
        }
    }]
    

    }
    }]

  • test:/.(png|jpg|gif)/是匹配图片文件后缀名称。

  • use:是指定使用的loader和loader的配置参数。

  • limit:是把小于500000B的文件打成Base64的格式,写入JS。

===============================================================

css分离

  • 安装插件 extract-text-webpack-plugin
  • 引入插件
  • 在插件中声明
  • 修改处理css
  • rules:[
    {
    test:/.css$/,
    use:extractTextPlugin.extract({
    fallback:'style-loader',
    use:'css-loader'
    })
    }]

===================================================================

处理html中的图片

  • 安装插件 html-withimg-loader
  • 配置插件
    >{
    test:/.(html|htm)$/i,
    use:['html-withimg-loader']
    }


====================================================================

自动补全css前缀

  • 安装插件 postcss-loader autoprefixer

  • 创建postcss.config.js

    module.exports={
    plugins:[

    require('auotprefixer')
    

    ]
    }

  • 编写loader

    {
    test: /.css$/,
    use: extractTextPlugin.extract({

    fallback: 'style-loader',
    use: [
        { loader: 'css-loader', options: { importLoaders: 1 } },
        'postcss-loader'
    ]
    

    })

}

git@github.com:heavenswen/webpack-page.git

//编译状态
const Env = process.env.NODE_ENV === 'production'
const { join, resolve } = require('path')
const webpack = require('webpack')
const glob = require('glob')
// const ImageminPlugin = require('imagemin-webpack-plugin').default;
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin')
const LiveReloadPlugin = require('webpack-livereload-plugin')
const ROOT = process.cwd();  // 根目录
// 通过允许您并行转换多个文件, HappyPack使Webpack构建更快。
const HappyPack = require('happypack');
const HappyThreadPool = HappyPack.ThreadPool({ size: (Env ? 10 : 4) });
const release = Env ? '/' : '/'//域名文件夹
//页面对应路口
const entries = {}
//入口对象集
const chunks = []
//页面list
const pagesList = []
//logo
const favicon = "./src/assets/img/logo.png"
// 页面模版
const entryHtml = []

//页面模版
glob.sync("./src/pages/**/*.{ejs,html}").forEach(path => {
  //HtmlWebpackPlugin 不支持 .html 编译 ejs 用.ejs
  let filename = path.split('./src/pages/')[1]

  //入口js文件名
  let chunk = path.split('./src/pages/')[1].split(/\.(ejs|html)/)[0]
  //设置产出路径
  chunk = 'js/' + chunk
  // 入口js路径
  let js = path

  //js路径
  js = js.replace(/\/pages/ig, '/entry');
  js = js.replace(/\.(ejs|html)/gi, '.js');
  entries[chunk] = js
  //入口js名称名称
  chunks.push(chunk)

  filename = filename.replace(/\.ejs/ig, '.html')
  //获得所有页面
  pagesList.push(filename)
  let htmlConf = {
    filename: filename,//文件名
    //模版位置
    template: path,
    inject: 'body',
    favicon: favicon,
    hash: Env,
    env: Env,//HtmlWebpackPlugin.options.env 非打包时的处理
    list: pagesList,//页面地址
    chunks: ['vendors', chunk] //chunk
  }

  //保存配置
  entryHtml.push(htmlConf)

})

const config = {
  entry: entries,
  output: {
    path: resolve(__dirname, './dist'),
    filename: '[name].js',
    publicPath: release
  },
  resolve: {
    //路径检索
    extensions: ['.js', '.vue'],
    alias: {
      //资源
      assets: join(__dirname, '/src/assets'),
      //组件
      components: join(__dirname, '/src/components'),
      //视图
      views: join(__dirname, '/src/views'),
      root: join(__dirname, 'node_modules')

    }
  },
  module: {
    //忽略以下js
    noParse: /node_modules\/(jquey|zepto|moment|chart\.js)/,
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader'
      },
      {
        test: /\.js$/,
        use: [{
          loader: 'babel-loader?id=js',
          options: {
            //es6
            presets: ['es2015']
          }
        }],
        exclude: /node_modules/
      },
      {
        //编译sass
        test: /\.(scss|sass)$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader?id=style',
          use: [{
            loader: 'css-loader?id=style',
            options: {
              //压缩css
              minimize: Env
            }
          }, 'postcss-loader?id=style', 'sass-loader?id=style'],
        })

      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader?id=style',
          use: [{
            loader: 'css-loader?id=style',
            options: {
              //压缩css
              minimize: Env
            }
          }, 'postcss-loader?id=style'],
        })
      },

      {
        //修改html img路径
        test: /\.html$/,
        use: [{
          loader: 'html-loader',
          options: {
            root: resolve(__dirname, 'src'),
            attrs: ['img:src', 'img:data-src', 'img:data-background', 'link:href']
          }
        }]
      },
      {
        test: /\.(png|jpg|jpeg|gif|svg|svgz)(\?.+)?$/,
        exclude: /favicon\.(png|ico)$/,//除外
        loaders: [
          'url-loader?limit=1000&outputPath=assets/img/&name=[name].[ext]?[hash]',
          {
            //图片压缩
            loader: 'image-webpack-loader',
            options: {
              gifsicle: {
                interlaced: false,
              },
              optipng: {
                optimizationLevel: 1,
              },
              pngquant: {
                quality: '65-90',
                speed: 4
              },
              mozjpeg: {
                progressive: true,
                quality: 65
              }
            }
          }
        ]
      },
      {
        //文字资源
        test: /\.(eot|ttf|woff|woff2)(\?.+)?$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 1000,
            name: "[name].[ext]?[hash]",
            outputPath: "assets/fonts/",//产出目录
          }
        }]
      },
      {
        //资源
        test: /\.(apk|docx|doc|exe)(\?.+)?$/,
        use: [{
          loader: 'file-loader',
          options: {
            name: "[name].[ext]?[hash]",
            outputPath: "assets/file/",//产出目录
          }
        }]
      }
    ]
  },
  plugins: [
    //会跟 webpack-dev-server 冲突,导致js修改时找不到修改对象
    // new LiveReloadPlugin({
    // }),
    new HappyPack({
      id: 'js',
      // @see https://github.com/amireh/happypack
      threadPool: HappyThreadPool,
      loaders: ['babel-loader']
    }),
    new HappyPack({
      id: 'styles',
      threadPool: HappyThreadPool,
      loaders: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader']
    }),
    //获取公用模块生成js
    new CommonsChunkPlugin({
      name: 'vendors',
      filename: 'assets/js/vendors.js?[hash]',
      chunks: chunks,
      minChunks: chunks.length
    }),
    //提取公用模块生成css
    new ExtractTextPlugin({
      filename: (getPath) => {
        //获得地址
        let name = getPath('[name]')

        if (!name.match(/vendors/ig)) {
          let arr = name.split('/')
          name = arr[arr.length - 1]//获得文件名
        }
        return 'assets/css/' + name + '.css';
      },
      allChunks: true
    }),
    //webpack3.0
    new webpack.optimize.ModuleConcatenationPlugin()
  ],
  devServer: {
    contentBase: [
      join(ROOT, 'src/')
    ],
    port: 8010,
    //启动路由功能
    //historyApiFallback: false,
    // noInfo: true,
    hot: false,
    //真实地址 可以用局域访问
    disableHostCheck: true,
    //允许其他电脑访问
    host: '0.0.0.0',
  },
  devtool: '#eval-source-map'
}


//页面模版
entryHtml.forEach(function (v) {
  config.plugins.push(new HtmlWebpackPlugin(v));
});

module.exports = config

if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  // http://vue-loader.vuejs.org/en/workflow/production.html
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    //压缩单元
    new webpack.optimize.UglifyJsPlugin({
      // 最紧凑的输出
      beautify: false,
      // 删除所有的注释
      comments: false,
      compress: {
        // 在UglifyJs删除没有用到的代码时不输出警告
        warnings: false,
        // 删除所有的 `console` 语句
        // 还可以兼容ie浏览器
        drop_console: true,
        // 内嵌定义了但是只用到一次的变量
        collapse_vars: true,
        // 提取出出现多次但是没有定义成变量去引用的静态值
        reduce_vars: true,
      }
    }),

  ])
}
var path = require('path');
var fs = require('fs');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');

console.log('NODE_ENV',process.env.NODE_ENV);

const extractCSS = new ExtractTextPlugin('css/[name]-one.css');
const extractLESS = new ExtractTextPlugin('css/[name]-two.css');
const extractSASS = new ExtractTextPlugin('css/[name]-three.css');

var config = {
    entry: {
        main: [
            // 'babel-polyfill',
            'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true',
            'webpack/hot/dev-server',
            path.resolve(__dirname, 'src/main.js'),
            path.resolve(__dirname, 'src/index.js')
        ],
        verdor: [
            path.resolve(__dirname, 'src/verdor/verdor.js'),
        ]
    },
    // entry: path.resolve(__filename, '../src/main.js'),
    output: {
        path: path.resolve(__filename, '../dist'),
        publicPath: '/',
        filename: '[name].[hash:8].bundle.js',
        // webpack 允许你根据文件内容生成哈希值,只要用 [chunkhash] 替换 [hash] 就可以了
        // 不要在开发环境下使用 [chunkhash],因为这会增加编译时间。将开发和生产模式的配置分开,并在开发模式中使用 [name].js 的文件名, 在生产模式中使用 [name].[chunkhash].js 文件名。
        //    publicPath: '/',
        //    chunkFilename: '[id].[chunkhash].js'
    },
    // 生成.map文件
    // devtool: 'source-map',
    module: {
        rules: [
            // 加载JSON文件 使用json-loader webpack1
            // wenpack2 + ,json-loader 不再需要手动添加
            // [官方: 是为了消除 webpack、 node.js 和 browserify 之间的环境差异。 https://github.com/webpack/webpack/issues/3363]
            // {
            //     test: /\.json$/,
            //     use: 'json-loader'
            // },

            // 处理 .json5结尾的文件
            {
                test: /\.json5$/,
                use: 'json5-loader'
            },
            // {
            //     test: /\.css$/,
            //     // 使用①生成的css文件 插入到html中
            //     // use: [ 'style-loader', 'css-loader' ]
            //     // 使用②ExtractTextPlugin 生成style.css文件
            //     // 在主入口文件中import
            //     use: ExtractCSS.extract([
            //         'css-loader',
            //         // 'px2rem2-loader',
            //         'postcss-loader',
            //     ]),
            // }

            // 使用postcss方式, css 插入到DOM形式 , 支持热更新
            // {
            //     test: /\.css$/,
            //     use: [ 'style-loader', 'css-loader',  'postcss-loader' ]
            // },
            {
                test: /\.less$/,
                use: extractLESS.extract({
                    fallback: ['style-loader'],
                    use: [
                        'css-loader',
                        'postcss-loader',
                        'less-loader'
                    ]
                })
            },
            {
                test: /\.scss$/,
                use: extractSASS.extract({
                    fallback: ['style-loader'],
                    use: [
                        'css-loader',
                        'postcss-loader',
                        'sass-loader'
                    ]
                })
            },
            // ExtractTextPlugin 提取了样式出来, 官方说No Hot Module Replacement。
            // https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/webpack-1/README.md
            {
                test: /\.css$/,
                use: extractCSS.extract({
                    fallback: ['style-loader'],
                    use: [
                        'css-loader',
                        'postcss-loader'
                    ]
                })
            },
            {
                test: /\.js(x)*$/,
                exclude: /node_modules/,
                loader: 'babel-loader'
            },
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 8000,
                    name: 'image/[name].[hash:7].[ext]'
                }
            },
            {
                test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 8000,
                    name: 'font/[name].[hash:7].[ext]'
                }
            },
            // 手写一个简单的webpack loader
            // 处理 .huangyb 后缀的文件
            {
                test: /\.huangyb$/,
                loader: 'huangyb-loader'
            }
        ]
    },
    plugins: [
        // 生成html文件,里面的JS文件 src 地址自动添加hash
        new HtmlWebpackPlugin({
            title: 'huangyb',
            favicon: './src/image/logoNew.gif',
            filename: 'index.html',
            minify:{
                removeComments: true, // 删除注释
                collapseWhitespace: true // 删除空格
            }
        }),
        // CSS生成单独的文件
        // new ExtractTextPlugin({
        //     filename: 'css/[name][hash:8].css',
        //     allChunks: true,
        //     disable: false
        // })

        extractCSS,
        extractLESS,
        extractSASS,

        // 用来跳过编译时出错的代码并记录,使编译后运行时的包不会发生错误
        // * webpack3 NoEmitOnErrorsPlugin 已经 取代webpack 2 的 NoErrorsPlugin
        new webpack.NoEmitOnErrorsPlugin(),
        new FriendlyErrorsWebpackPlugin(), // 终端显示

        new webpack.optimize.CommonsChunkPlugin({ // 提取公用JS代码插件
            names: ['vendor'],
            // ( 公共chunk(commnons chunk) 的名称)
            filename: 'commons.js',
            // ( 公共chunk 的文件名)
            minChunks: 3
            // (模块必须被3个 入口chunk 共享)
            // CommonsChunkPlugin 可以通过传参minChunks来控制你希望重复出现几次的module 被提取出来打包。
            // 也就是说你自己可以控制当一个模块被引入几次可以被打包到共用的chunk中,还可以规定如果这个公共模块小于一个值 minSize,
            // 就不被提取出来这些都可以帮助你控制你想要的粒度。当你改的不是公共模块的代码,理论上webpack 打包的时候本来就不会影响其他代码。
            // chunks: ['pageA', 'pageB'],
            // (只使用这些 入口chunk)
        }),

        // OccurrenceOrderPlugin 现在默认启用,并已重命名(在 webpack 1 中为 OccurenceOrderPlugin)。 因此,请确保从您的配置中删除该插件:
        // OccurrenceOrderPlugin is now on by default
        // new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin()
    ]
    // resolve: {
    //     alias: {
    //         huangImg: path.resolve(__dirname, 'src/image/')
    //     }
    // }
}

module.exports = config;
/*
 * @Author: ignaciozhu
 * @Date: 2017-05-03 16:32:21
 * @Last Modified by: ignaciozhu
 * @Last Modified time: 2017-06-02 11:50:06
 */
//配置本地反向代理文件夹所在路径
const DIST = '../../../ya/client_html/branch/nginx-1.10.1/';
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require("html-webpack-plugin") //自动生成一个html 引入打包之后的js
const ExtractTextPlugin = require("extract-text-webpack-plugin") //默认打包css 这些全部在js 里面  用这个可以分离出来 单独生成css文件  //生产环节会用到
const OpenBrowserPlugin = require('open-browser-webpack-plugin') //打包完成自动打开浏览器
const CopyWebpackPlugin = require('copy-webpack-plugin') //拷贝文件  当有第三方依赖可以copy到打包文件夹中
const autoprefixer = require('autoprefixer') //自动加前缀
const CptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') //压缩css
const ImageminPlugin = require('imagemin-webpack-plugin').default //压缩图片
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') //生成打包图
const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); //webpack3 单独分离出来了这个压缩的

const { host, dev_port } = require("./config")
const { delhttp } = require('./server/utils/method.js')

module.exports = (env) => {
  //env 是npm script 运行webpack时传进来的  判断是否是开发环境
  const mode = (env && env.mode) || "DEV"

  const options = {
      //开发工具
      devtool: mode === "DEV" ? "source-map" : false,

      //开发服务器
      devServer: {
        contentBase: path.resolve(__dirname, "dist"), //静态资源根目录
        compress: true, //压缩
        port: dev_port, //端口
        host: delhttp(host),
        hot: true, //热更新
        inline: true, //iframe 模式
        historyApiFallback: true, //浏览器 history
        stats: { //统计
          color: true, //输出有颜色的信息
          errors: true, //显示错误信息
          version: true, //显示版本号
          warnings: true, //显示警告
          progress: true, //显示进度,
          timings: true, //显示时间
        }
      },

      //入口
      entry: mode === "DEV" ? [
        "react-hot-loader/patch", //热更新
        `webpack-dev-server/client?${host}:${dev_port}`,
        "webpack/hot/only-dev-server",
        path.resolve(__dirname, "src/index.js"),
      ] : {
        app: path.resolve(__dirname, "src/index.js"),
        // vendor:['react']
      },

      //打包输出
      output: {
        path: path.resolve(__dirname, DIST + "dist"), ///myblog
        filename: mode === "DEV" ? "js/[name].js" : "./js/[name].[chunkhash:8].js",
        chunkFilename: mode === "DEV" ? "js/[name]Chunk.js" : "./js/[name]Chunk.[chunkhash:8].js",
        publicPath: mode === "DEV" ? `${host}:${dev_port}/` : "/" //myblog/
      },

      //模块加载器
      module: {
        rules: [{
          test: /\.js[x]?$/,
          use: [{
            loader: "babel-loader"
          }],
          exclude: "/node_modules/",
          use: [
            // {loader:'react-hot-loader'},
            {
              loader: "babel-loader",
              options: {
                //按需加载模块,antd...
                plugins: [
                  ["import", [{
                    "libraryName": "antd",
                    "libraryDirectory": "lib",
                    "style": true
                  }, {
                    "libraryName": "antd-mobile",
                    "libraryDirectory": "component",
                  }, ]],
                  // "transform-decorators-legacy",
                  // "transform-class-properties"
                ]
              }
            },
          ],
          include: [path.resolve("src")] //只遍历src目录下的
        }, {
          test: /\.less$/,
          use: mode === "DEV" //开发环境 css打包到js中
            ? [
              { loader: "style-loader" }, //loader 倒序执行  先执行 less-laoder
              { loader: "css-loader", options: { minimize: false, sourceMap: true } },
              { loader: "postcss-loader" }, //自动加前缀
              { loader: "less-loader", options: { sourceMap: true } }
            ] : ExtractTextPlugin.extract({ //生产环境 把css单独分离出来
              fallback: "style-loader",
              use: [
                "css-loader",
                "postcss-loader", {
                  loader: "less-loader",
                  options: {
                    sourceMap: false,
                  },
                },
              ],
            })
        }, {
          test: /\.css$/,
          use: mode === "DEV" ? [
            { loader: "style-loader" }, //loader 倒序执行  先执行 less-laoder
            { loader: "css-loader", options: { minimize: false, sourceMap: true } },
            { loader: "postcss-loader" }
          ] : ExtractTextPlugin.extract({
            fallback: "style-loader",
            use: [
              "css-loader",
              "postcss-loader", {
                loader: "less-loader",
                options: {
                  sourceMap: false
                },
              },
            ],
          })
        }, {
          test: /\.(jpg|jpeg|png|gif|cur|ico)$/,
          use: [{
            loader: 'file-loader',
            options: {
              name: "images/[name][hash:8].[ext]" //遇到图片  生成一个images文件夹  名字.后缀的图片
            }
          }]
        }, {
          test: /\.(eot|ttf|svg|woff|woff2)$/,
          use: [{
            loader: "file-loader",
            options: {
              name: "fonts/[name][hash:8].[ext]",
            },
          }, ],
        }, ]
      },

      //自动补全后缀
      resolve: {
        enforceExtension: false, //2.0 后 不能写 extensions :[""]
        extensions: ['.js', '.jsx', '.json'], //比如 test.js   可以写成 require('test')
        alias: {
          // Support React Native Web
          // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
          'react-native': 'react-native-web',
          components: path.resolve(__dirname) + '/src/common/components',
          /* container: path.resolve(__dirname, '..') + '/src/common/container',
           images: path.resolve(__dirname, '..') + '/src/common/images',
           pages: path.resolve(__dirname, '..') + '/src/common/pages',
           utils: path.resolve(__dirname, '..') + '/src/common/utils',
           data: path.resolve(__dirname, '..') + '/src/server/data',
           actions: path.resolve(__dirname, '..') + '/src/common/actions',
           reducers: path.resolve(__dirname, '..') + '/src/common/reducers',*/
        },
        modules: [
          path.resolve("src"), //比如 src/app/components/xx  可以写成 app/components/xx
          path.resolve("."),
          path.resolve("src/shared"),
          "node_modules",
        ],
      },

      //插件
      plugins: []
    }
    //根据开发环境不同  concat 不同的插件
  if (mode === "DEV") {
    options.plugins = options.plugins.concat([
      new webpack.NamedModulesPlugin(), //打印更具可读性模块名称在浏览器控制台
      new webpack.NoEmitOnErrorsPlugin(), //错误不打断
      new webpack.DefinePlugin({ //调试
        __DEBUG__: true,
      }),
      new webpack.HotModuleReplacementPlugin(), //热加载插件
      /*      new OpenBrowserPlugin({ //编译完成打开浏览器
              url: `${host}:${dev_port}`
            })*/
    ])
  } else {
    options.plugins = options.plugins.concat([
      // new BundleAnalyzerPlugin(),     //生成打包图
      // //webpackv3.0新增 作用域提升 默认是闭包式打包 浏览器执行速度变慢
      // //开启这个去掉模块的包裹函数,体积更小
      // new webpack.optimize.ModuleConcatenationPlugin(),
      new webpack.DefinePlugin({
        "process.env.NODE_ENV": JSON.stringify("production"),
        __DEBUG__: false,
      }),
      new UglifyJSPlugin({ //压缩
        output: {
          comments: false //移除所有注释
        },
        compress: {
          warnings: false
        }
      }),
      new ExtractTextPlugin({ // 将打包文件中的css分离成一个单独的css文件
        filename: 'css/app.[contenthash:8].css',
        allChunks: true
      }),
      //[1]
      //找到所有node_modules的依赖包  分离出来
      // /axios/ 没有用到的模块
      new webpack.optimize.CommonsChunkPlugin({
        name: "app",
        async: "common-in-lazy",
        children: true,
        minChunks: ({ resource } = {}) => (
          resource &&
          resource.includes('node_modules') &&
          /axios/.test(resource)
        )
      }),
      // [2]
      //找到模块次数使用两次的  分离出来
      //单独打成used-twice.js 减少包的体积
      /**
       * 升级到 v2.6 貌似async不起作用  article admin detail 都使用了但是moment都打包进了对应的chunk文件
       * 导致文件增大了600kb
       * 经过github上的提问 各路大神的帮助下  解决了上面这个问题 需要设置name!!!!!!!!!!!
       */
      new webpack.optimize.CommonsChunkPlugin({
        name: "app",
        children: true,
        async: 'used-twice',
        minChunks: (module, count) => (
          count >= 2
        ),
      }),
      //[3]
      //[1][2][3] 是按需加载 大幅减少打包js体积的关键
      //遍历node_modules目录 以.js结尾 一道vender chunk
      //自动化分离第三方依赖
      new webpack.optimize.CommonsChunkPlugin({
        name: 'app',
        filename: "js/common.[chunkhash:8].js",
        minChunks: ({ resource }) => (
          resource &&
          resource.indexOf('node_modules') >= 0 &&
          resource.match(/\.js$/)
        )
      }),
      new webpack.LoaderOptionsPlugin({ //laoder最小化
        minimize: true
      }),
      //图片压缩没用。。。什么鬼
      new ImageminPlugin({
        // disable:false,
        test: /\.(jpe?g|png|gif|svg)$/i,
        optipng: {
          optimizationLevel: 7
        }
      }),
      new CptimizeCssAssetsPlugin({ //压缩css  与 ExtractTextPlugin 配合使用
        cssProcessor: require('cssnano'),
        cssProcessorOptions: { discardComments: { removeAll: true } }, //移除所有注释
        canPrint: true //是否向控制台打印消息
      })
    ])
  }
  options.plugins.push(
    new HtmlWebpackPlugin({
      title: "西溪泊岸共享",
      filename: "index.html", //自动把打包的js文件引入进去
      template: path.resolve(__dirname, "src/index.html"), //模板文件
      hash: true, //添加hash码
      inject: true //注射所有资源到 body元素的底部     "head" "body" true false  "body" == true
    })
  )
  return options
}
`