多页面webpack配置

工程结构如下 

dev-server

const config = require('../config');
const express = require('express');
const path = require('path');
const fs = require('fs');
// const favicon=require('serve-favicon');
const exec = require('child_process').exec;
process.env.NODE_ENV = config.dev.env.NODE_ENV;
console.log(config)
const webpack = require('webpack');
const webpackConfig = require('./webpack.config.dev');

webpack(webpackConfig, function(err, stats, errStates) {
    process.stdout.write(stats.toString({
        colors: true,
        modules: false,
        children: false,
        chunks: false,
        chunkModules: false
    }) + '
')
});

//#########
const app = express();
// app.use(webpackDevMiddleware(compiler, {
//   hot:false
//   options
// }));

app.get("/", renderHtml);
app.get("/:file", renderHtml);
// app.use(favicon(path.join(__dirname, '../dist/public', 'favicon.ico')));
app.use(express.static(path.join(__dirname, '../dist')));

function renderHtml(req, res) {
    // res.header("Access-Control-Allow-Origin","*");
    // res.header("Access-Control-Allow-Headers", "x-csrf-token");
    // res.header("Access-Control-Allow-Headers", "Access-Token");
    let fileName = req.params.file;
    if (!fileName) fileName = "index.html";
    fileName = fileName.split(".html")[0];
    fs.readFile(path.join(__dirname, '../src/modules/' + fileName + '/' + fileName + '.html'), function(err, data) {
        // body
        if (err) {
            console.log(err);
            //404:NOT FOUND
            res.writeHead(404, { "Content-Type": "text/html" });
        } else {
            //200:OK
            res.writeHead(200, { "Content-Type": "text/html" });
            res.write(data.toString());
        }
        res.end();
    });
}

const server = app.listen(3300, function() {
    console.log("listening on port 3300")
});
pack-beta

const config = require('../config');
const delFiles  = require('./utils').delFiles;
process.env.NODE_ENV = config.beta.env.NODE_ENV;
const exec = require('child_process').exec;

const webpack = require('webpack');
const webpackConfig = require('./webpack.config.beta');

webpack(webpackConfig,function (err, stats) {
  console.log(err);
  process.stdout.write(stats.toString({
    colors: true,
    modules: false,
    children: false,
    chunks: false,
    chunkModules: false
  }) + '
');
  // exec("gulp", function (err, str, strerr) {
  //   console.log(str);
  // });
}); 
pack-prod

const config = require('../config');
const delFiles  = require('./utils').delFiles;
process.env.NODE_ENV = config.prod.env.NODE_ENV;
const exec = require('child_process').exec;

const webpack = require('webpack');
const webpackConfig = require('./webpack.config.prod');

//delFiles("../dist/js");
//delFiles("../dist/css");
webpack(webpackConfig,function (err, stats) {
  console.log(err);
  process.stdout.write(stats.toString({
    colors: true,
    modules: false,
    children: false,
    chunks: false,
    chunkModules: false
  }) + '
');
  // exec("gulp", function (err, str, strerr) {
  //   console.log(str);
  // });
});
utils

const path = require('path');
const fs = require('fs');
const htmlWebpackPlugin = require('html-webpack-plugin');


module.exports = {
  delFiles: function (route) {
    let p = path.resolve(__dirname, route);
    let files = fs.readdirSync(p);
    for (let i = 0; i < files.length; i++) {
      del(p + "/" + files[i])
    }
    function del(file) {
      fs.unlinkSync(file);
      fs.existsSync(file);
    }
    return true;
  },
  ergodicFiles:function (dirPath) {
    let l = [];
    let p = path.resolve(__dirname, dirPath);
    fs.readdirSync(p).forEach(function(file,i){
      l.push(file);
      // l.push({name:file,path:p});
    });
    return l;
  },
  ergodicEntry:function (dirPath) {
    let l = {};
    let p = path.resolve(__dirname, dirPath);
    fs.readdirSync(p).forEach(function(file,i){
      l[file] = [p+'/'+file+'/'+file+'.js']
    });
    return l;
  },
  getHTMLList:function (dirPath) {
    let obj = this.ergodicEntry(dirPath);
    let extra = this.extraResource();
    let ha=[];
    for (let key in obj) {
      ha.push(
        new htmlWebpackPlugin({
          template: 'index.html',
          filename: key + ".html?[hash]",
          fileId: key,
          cache:false,
          env:process.env.NODE_ENV,
          time:this.dealTime(new Date(),"yyyy-mm-dd hh:mm","-"),
          extra:(function () {
            if(extra[key]){
              return extra[key];
            }else{
              return [];
            }
          })(),
          chunks: ['jquery', 'vue', 'common', key]
        })
      )
    }
    return ha;
  },
  source:function(){
    let path = "http://cdn2.test.dianjingquan.cn";
    if(process.env.NODE_ENV === 'production') path = "http://cdn2.test.dianjingquan.cn";
    return {
      cropper:'<script src="'+path+'/js/cropper.js"></script>',//截图插件
      snapSvg:'<script src="'+path+'/js/snap.svg-min.js"></script>',//svg动画
      swiper:'<script src="'+path+'/js/swiper-3.4.2.jquery.min.js"></script>',//swap动画效果
      jsEncrypt:'<script src="'+path+'/js/jsencrypt.js"></script>',
      pageWalkThrough:'<script src="'+path+'/js/jquery.pagewalkthrough.min.js"></script>',
      jqueryUiWidget:'<script src="'+path+'/js/jquery.ui.widget.js"></script>',
      jqueryFileUpload:'<script src="'+path+'/js/jquery.fileupload.js"></script>',//jquery图片上传插件
      qrcode:'<script src="'+path+'/js/qrcode.min.js"></script>',//生成二维码插件
      jedate:'<script src="'+path+'/jedate/jquery.jedate.min.js"></script>',//日历插件
      emoji:'<script src="'+path+'/js/emoji.js"></script>',//emoji表情
      gt:'<script src="'+path+'/js/gt.js"></script>',
      moxie:'<script src="'+path+'/js/moxie.js"></script>',
      plupload:'<script src="'+path+'/js/plupload.dev.js"></script>'
    };
  },
  extraResource:function () {
    let s =this.source();
    return {
      index:[s.swiper,s.jsEncrypt],
      matchDetail:[s.pageWalkThrough,s.jqueryUiWidget,s.jqueryFileUpload,s.qrcode,s.snapSvg],
      createMatch:[s.cropper,s.jedate],
      userCenter:[s.cropper,s.emoji],
      entryList:[s.cropper],
      login:[s.cropper,s.jsEncrypt,s.gt],
      personalProfile:[s.cropper,s.gt,s.jsEncrypt,s.moxie,s.plupload],
      previewAgainst:[s.snapSvg],
      sample:[s.cropper],
      share:[s.qrcode],
      vsAgainst:[s.snapSvg]
    }
  },
  dealTime : function (time, type, o) {
    let tt = new Date(time);
    switch (type) {
      case "yyyy-mm-dd hh:mm":
        return tt.getFullYear() + o + ((tt.getMonth() + 1) < 10 ? '0' + (tt.getMonth() + 1) : (tt.getMonth() + 1)) + o + (tt.getDate() < 10 ? '0' + tt.getDate() : tt.getDate()) + " " + tt.getHours() + ':' + (tt.getMinutes() < 10 ? '0' + tt.getMinutes() : tt.getMinutes());
      case 'yyyy-mm-dd':
        return tt.getFullYear() + o + ((tt.getMonth() + 1) < 10 ? '0' + (tt.getMonth() + 1) : (tt.getMonth() + 1)) + o + (tt.getDate() < 10 ? '0' + tt.getDate() : tt.getDate());
      case 'mm-dd':
        if (o) {
          return tt.getMonth() + 1 + o + tt.getDate();
        } else {
          return tt.getMonth() + 1 + "月" + tt.getDate() + "日";
        }
      case 'hh:mm':
        return tt.getHours() + ':' + (tt.getMinutes() < 10 ? '0' + tt.getMinutes() : tt.getMinutes())
    }
  }
};
webpack.base

const path = require('path');
const util = require('./utils');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
function resolve (dir) {
  return path.join(__dirname, '..', dir)
}
let vueOption = {
  test: /.vue$/,
  loader: 'vue-loader',
  // options: {
  //   loaders: {
  //     css: ExtractTextPlugin.extract({
  //       fallback: "vue-style-loader",
  //       use: "css-loader"
  //     }),
  //     scss: ExtractTextPlugin.extract({
  //       fallback: "vue-style-loader",
  //       use: "css-loader!sass-loader"
  //     }),
  //   }
  // }
};
if(process.env.NODE_ENV === 'beta' || process.env.NODE_ENV === 'prod'){
  vueOption = {
    test: /.vue$/,
    loader: 'vue-loader',
    options: {
      loaders: {
        css: ExtractTextPlugin.extract({
          fallback: "vue-style-loader",
          use: "css-loader"
        }),
        scss: ExtractTextPlugin.extract({
          fallback: "vue-style-loader",
          use: "css-loader!sass-loader"
        }),
      }
    }
  }
}
module.exports = {
  entry: Object.assign(
    util.ergodicEntry('../src/modules'),
    {
      jquery : ["jquery"],
      vue : ["vue"],
    }),//值可以是字符串、数组或对象,
  module: {
    rules: [
      vueOption,
      {
        test: /.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        query:{
        }
      },
      {
        test: /.(png|jpg|gif|svg)$/,
        loader: 'file-loader',
        options: {
          name: 'images/[name].[ext]?[hash]'
        }
      },
      {
        test: /.(woff|eot|ttf|otf)$/,
        loader: 'url-loader',
        options: {
          name: '[name].[ext]?[hash]'
        }
      },
      {
        test: /.css$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader"
        })
      },
      {
        test: /.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader!sass-loader"
        })
      },
      // {
      //   test: /.(css|scss)$/,
      //   loader: "style-loader!css-loader!!sass-loader",
      // }
    ]
  },
  resolve: {
    alias: {
      'env':(function (env) {
        if (env === 'beta') return resolve('config/env-beta.js');
        else if (env === 'prod') return resolve('config/env-prod.js');
        else return resolve('config/env-dev.js');
      })(process.env.NODE_ENV),
      '$':'jquery',
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
    extensions: ['.ts', '.js','.vue','.css','.scss']
  }
};
webpack.beta
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
const util = require('./utils');

module.exports = merge(baseWebpackConfig,{
  output: {
    path: path.resolve(__dirname, '../build/beta'),//Webpack结果存储
    publicPath: '/',//用于在生产模式和开发模式下下更新内嵌到css、html,img文件里的url值
    filename: 'js/[name]-[hash].js',
    chunkFilename: './js/[name]-[hash].js'
  },
  plugins: [
    new ExtractTextPlugin("css/[name]-[hash].css"),
    new CommonsChunkPlugin({name:["common","jquery","vue"],filename:"js/[name]-[hash].js",minChunks:2}),
    ...util.getHTMLList('../src/modules'),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress: {
        warnings: false,
        drop_debugger: true,
        drop_console: true
      }
    }),
  ],
  devServer: {//webpack-dev-server配置
    historyApiFallback: true,//不跳转
    noInfo: true,
    inline: true//实时刷新
  },
  performance: {
    hints: false
  },
  // compress: {
  //   warnings: false, // 去除warning警告
  //   drop_debugger: true, // 发布时去除debugger语句
  //   drop_console: true // 发布时去除console语句
  // },
  // devtool: '#eval-source-map'
});

// 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({
//       sourceMap: true,
//       compress: {
//         warnings: false
//       }
//     }),
//     new webpack.LoaderOptionsPlugin({
//       minimize: true
//     })
//   ])
// }
webpack.dev
const path = require('path');
const merge = require('webpack-merge');
const webpack = require('webpack');
const baseWebpackConfig = require('./webpack.base');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const util = require('./utils');
module.exports = merge(baseWebpackConfig,{
  output: {
    path: path.resolve(__dirname, '../dist'),//Webpack结果存储
    publicPath: '../',//用于在生产模式和开发模式下下更新内嵌到css、html,img文件里的url值
    filename: 'js/[name].js'
  },
  plugins: [
    new ExtractTextPlugin("css/[name].css"),
    // ...util.getHTMLList('../src/modules'),
  ],
  devServer: {//webpack-dev-server配置
    historyApiFallback: true,//不跳转
    noInfo: true,
    // inline: true//实时刷新
  },
  performance: {
    hints: false
  },
  watch:true,
  watchOptions:{
    // ignored: [/node_modules/,/dist/]
  }
  // devtool: '#eval-source-map'
});
webpack.prod
const path = require('path');
const merge = require('webpack-merge');
const webpack = require('webpack');
const baseWebpackConfig = require('./webpack.base');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const util = require('./utils');
module.exports = merge(baseWebpackConfig,{
  output: {
    path: path.resolve(__dirname, '../dist'),//Webpack结果存储
    publicPath: '../',//用于在生产模式和开发模式下下更新内嵌到css、html,img文件里的url值
    filename: 'js/[name].js'
  },
  plugins: [
    new ExtractTextPlugin("css/[name].css"),
    // ...util.getHTMLList('../src/modules'),
  ],
  devServer: {//webpack-dev-server配置
    historyApiFallback: true,//不跳转
    noInfo: true,
    // inline: true//实时刷新
  },
  performance: {
    hints: false
  },
  watch:true,
  watchOptions:{
    // ignored: [/node_modules/,/dist/]
  }
  // devtool: '#eval-source-map'
});
config 文件夹
index.js

// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path');

module.exports = {
  beta: {
    env: {NODE_ENV:'beta'},
  },
  dev: {
    env: {NODE_ENV:'development'},
  },
  prod: {
    env: {NODE_ENV:'prod'},
  }
};
pack.json
{
  "name": "ees_web",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "node build_setting/dev-server.js",
    "pack-beta": "node build_setting/pack-beta.js",
    "pack-prod": "node build_setting/pack-prod.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "babel-eslint": "^7.2.3",
    "babel-polyfill": "^6.26.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "babel-preset-stage-1": "^6.24.1",
    "child_process": "^1.0.2",
    "djq-component": "^1.0.1",
    "echarts": "^3.8.5",
    "es6-promise": "^4.1.1",
    "express": "^4.16.2",
    "extract-text-webpack-plugin": "^3.0.2",
    "gulp": "^3.9.1",
    "gulp-inject": "^4.2.0",
    "gulp-minify": "^1.0.0",
    "gulp-sequence": "^0.4.6",
    "jquery": "^3.2.1",
    "node-sass": "^4.7.2",
    "sass-loader": "^6.0.6",
    "ts-loader": "^2.3.4",
    "vee-validate": "^2.0.0-rc.19",
    "vue": "^2.4.2",
    "vue-cli": "^2.8.2",
    "vue-cropper": "^0.2.5",
    "vue-infinite-loading": "^2.2.1",
    "vuex": "^2.4.0",
    "webpack-hot-middleware": "^2.19.1",
    "webpack-merge": "^4.1.1"
  },
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-es2015": "^6.24.1",
    "cropper": "^3.1.3",
    "css-loader": "^0.28.7",
    "file-loader": "^0.11.2",
    "style-loader": "^0.18.2",
    "stylus-loader": "^3.0.1",
    "url-loader": "^0.5.9",
    "vue-loader": "^13.0.4",
    "vue-router": "^2.7.0",
    "vue-template-compiler": "^2.4.2",
    "webpack": "^3.10.0",
    "webpack-dev-server": "^2.7.1"
  }
}
原文地址:https://www.cnblogs.com/lisiyang/p/8426067.html