sayll/ie-webpack-start

View on GitHub
config/webpack/webpack.config.js

Summary

Maintainability
A
1 hr
Test Coverage
const base              = require('./base/base.js'),
      files             = require('./base/files'),
      path              = require('path'),
      glob              = require('glob'),
      HtmlWebpackPlugin = require('html-webpack-plugin'),
      ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = (option = { dev: process.env.NODE_ENV === 'development' }) => ((Glob, objConcat, createHtml) => {

  /**
   * Config
   * */
  let Config = {
    entry: objConcat(Glob.fileCss, objConcat(Glob.fileJs, require('./modules/entry'))),
    resolve: require('./modules/resolve'),
    output: {
      path: path.join(files.root, files.buildName),
      publicPath: base.cdnPath, //资源文件引用路径
      filename: Glob.jsBundle,
      crossOriginLoading: false, // 是否允许跨域加载[anonymous,use-credentials,false]
      chunkFilename: 'async/[name].js',
      sourceMapFilename: '[file].map'
    },
    module: require('./modules/loader')(option.dev),
    plugins: require('./modules/plugins')
  };

  Config.plugins.push(new ExtractTextPlugin(Glob.cssBundle));

  /**
   * 创建所有的视图模块
   * */
  createHtml(Config, Glob.fileHtml, files.htmlPath, base.viewType, option.dev);
  return Config;
})(
  /**
   * 处理所需文件的文件目录,输出对应文件的对象
   * */
  ((debug) => {
    /**
     * 此变量用于匹配储存HTML对应模块
     * 非模块内的资源文件不会被webpack引入
     * */
    let VIEWS = [];

    function getEntry(option, VIEWS) {
      let pathDir = option.pathDir,
          files   = glob.sync(option.globPath);

      let entries = {},
          entry, // 文件完整路径
          dirName, // 传入的文件夹路径
          baseName, // 文件名
          pathName, // 文件夹路劲
          relativeName, // 键名所需,相对传入文件地址路径
          extName; // 文件格式

      for (let i = 0; i < files.length; i++) {
        entry = files[i];
        extName = path.extname(entry);
        dirName = path.dirname(entry);
        baseName = path.basename(entry, extName);
        pathName = path.normalize(path.join(dirName, baseName));
        pathDir = path.normalize(pathDir);
        if (extName === `.${base.viewType}`) { // 是否是view
          pathName = pathName.substring(pathDir.length);
          VIEWS.push(pathName); // 把VIEW相关的模块引入webpack
        }
        else {
          relativeName = path.relative(pathDir, dirName);
          pathName = path.basename(pathName);
          if (VIEWS.indexOf(relativeName) === -1 || relativeName.indexOf(pathName) === -1) {
            // 不属于HTML相关JS直接跳出循环
            continue;
          }
          else {
            pathName = relativeName;
          }
        }
        entries[pathName] = [entry];
      }
      return entries;
    }

    let fileHtml  = Object.keys(getEntry({
          globPath: files.htmlPath + '/**/*',
          pathDir: files.htmlPath + '/'
        }, VIEWS)),
        fileJs    = getEntry({
          globPath: files.viewPath + '/**/*.?(js|jsx)',
          pathDir: files.viewPath + '/'
        }, VIEWS),
        fileCss   = getEntry({
          globPath: files.viewPath + '/**/*.?(css|pcss|sass|scss|less)',
          pathDir: files.viewPath + '/'
        }, VIEWS),
        jsBundle  = debug ? `${files.jsName}/[name].js` : `${files.jsName}/[name].[chunkhash:8].js`,
        cssBundle = debug ? `${files.cssName}/[name].css` : `${files.cssName}/[name].[contenthash:8].css`;
    return {
      'fileHtml': fileHtml,
      'fileJs': fileJs,
      'fileCss': fileCss,
      'jsBundle': jsBundle,
      'cssBundle': cssBundle
    }
  })(option.dev),

  /**
   * 处理文件页面资源对应关系
   * */
  (obj1, obj2) => {
    Object.keys(obj1).forEach(function (o) {
      if (!!obj2[o] && obj2[o] !== obj1[o]) {
        obj2[o] = obj2[o].concat(obj1[o]);
      }
      else {
        obj2[o] = obj1[o]
      }
    });
    return obj2;
  },

  /**
   * config:webpack的config
   * htmlFiles: 某目录下的所有HTML对象
   * htmlPath:HTML视图地址
   * viewType:HTML模版引擎格式(如html,pug,jade)
   * dev: 是否开发模式,对应引入热替换模块
   * */
  (config, htmlFiles, htmlPath, viewType, debug) => {

    if (debug) {
      Object.keys(config.entry).forEach((e) => {
        config.entry[e].unshift(
          'webpack-hot-middleware/client?reload=true'
          //'eventsource-polyfill' // 热替换兼容IE
        )
      });
    }

    // 遍历创建所有HTML
    htmlFiles.forEach(function (pathname) {
      let conf = {
        filename: pathname + '.html', //生成的html存放路径,相对于path
        template: path.resolve(htmlPath, pathname + '.' + viewType), //html模板路径
        minify: {
          removeComments: true,
          collapseWhitespace: true,
          removeRedundantAttributes: true,
          useShortDoctype: true,
          removeEmptyAttributes: true,
          removeStyleLinkTypeAttributes: true,
          keepClosingSlash: true,
          minifyJS: true,
          minifyCSS: true,
          minifyURLs: true
        }
      };
      if (pathname in config.entry) { // 同HTML文件名的JS分离出来
        conf.inject = 'body';
        conf.chunks = ['Common', 'Main', pathname];
      }
      else {
        conf.inject = 'body';
        conf.chunks = ['Common', 'Main'];
      }
      conf.chunksSortMode = function (a, b) { // 按照配置排序
        let index = {}, i = 1,
            len           = conf.chunks.length;
        for (; i <= len; i++) {
          index[conf.chunks[len - i]] = i;
        }
        let aI = index[a.origins[0].name],
            bI = index[b.origins[0].name];
        return aI && bI ? bI - aI : -1;
      };
      config.plugins.push(new HtmlWebpackPlugin(conf));
    });
  });