"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = _default;

function _react() {
  const data = _interopRequireDefault(require("react"));

  _react = function _react() {
    return data;
  };

  return data;
}

function _webpack() {
  const data = require("webpack");

  _webpack = function _webpack() {
    return data;
  };

  return data;
}

function _webpackChain() {
  const data = _interopRequireDefault(require("webpack-chain"));

  _webpackChain = function _webpackChain() {
    return data;
  };

  return data;
}

function _path() {
  const data = require("path");

  _path = function _path() {
    return data;
  };

  return data;
}

function _fs() {
  const data = require("fs");

  _fs = function _fs() {
    return data;
  };

  return data;
}

function _os() {
  const data = require("os");

  _os = function _os() {
    return data;
  };

  return data;
}

function _assert() {
  const data = _interopRequireDefault(require("assert"));

  _assert = function _assert() {
    return data;
  };

  return data;
}

var _es5ImcompatibleVersions = require("./es5ImcompatibleVersions");

var _resolveDefine = _interopRequireDefault(require("./resolveDefine"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

// import send, { STARTING } from '../send';
function makeArray(item) {
  if (Array.isArray(item)) return item;
  return [item];
}

function _default(opts) {
  const _ref = opts || {},
        cwd = _ref.cwd;

  const isDev = opts.isDev || process.env.NODE_ENV === 'development';
  const webpackConfig = new (_webpackChain().default)(); // mode

  webpackConfig.mode('development'); // entry

  if (opts.entry) {
    // eslint-disable-next-line guard-for-in
    for (const key in opts.entry) {
      const entry = webpackConfig.entry(key);
      makeArray(opts.entry[key]).forEach(file => {
        entry.add(file);
      });
    }
  } // output


  const absOutputPath = (0, _path().resolve)(cwd, opts.outputPath || 'dist');
  webpackConfig.output.path(absOutputPath).filename(`[name].js`).chunkFilename(`[name].async.js`).publicPath(opts.publicPath || undefined).devtoolModuleFilenameTemplate(info => {
    return (0, _path().relative)(opts.cwd, info.absoluteResourcePath).replace(/\\/g, '/');
  }); // resolve

  webpackConfig.resolve // 不能设为 false，因为 tnpm 是通过 link 处理依赖，设为 false tnpm 下会有大量的冗余模块
  .set('symlinks', true).modules.add('node_modules').add((0, _path().join)(__dirname, '../../node_modules')) // Fix yarn global resolve problem
  .add((0, _path().join)(__dirname, '../../../')).end().extensions.merge(['.web.js', '.wasm', '.mjs', '.js', '.web.jsx', '.jsx', '.web.ts', '.ts', '.web.tsx', '.tsx', '.json']);

  if (opts.alias) {
    // eslint-disable-next-line guard-for-in
    for (const key in opts.alias) {
      webpackConfig.resolve.alias.set(key, opts.alias[key]);
    }
  } // resolveLoader


  webpackConfig.resolveLoader.modules.add('node_modules').add((0, _path().join)(__dirname, '../../node_modules')).end();

  if (!opts.disableDynamicImport && !process.env.__FROM_UMI_TEST) {
    webpackConfig.optimization.splitChunks({
      chunks: 'async',
      name: 'vendors'
    }).runtimeChunk(false);
  } // module -> exclude


  const DEFAULT_INLINE_LIMIT = 10000;
  const rule = webpackConfig.module.rule('exclude').exclude.add(/\.json$/).add(/\.(js|jsx|ts|tsx|mjs|wasm)$/).add(/\.(graphql|gql)$/).add(/\.(css|less|scss|sass|styl(us)?)$/);

  if (opts.urlLoaderExcludes) {
    opts.urlLoaderExcludes.forEach(exclude => {
      rule.add(exclude);
    });
  }

  rule.end().use('url-loader').loader(require.resolve('umi-url-pnp-loader')).options({
    limit: opts.inlineLimit || DEFAULT_INLINE_LIMIT,
    name: 'static/[name].[hash:8].[ext]'
  });
  const babelOptsCommon = {
    // Tell babel to guess the type, instead assuming all files are modules
    // https://github.com/webpack/webpack/issues/4039#issuecomment-419284940
    sourceType: 'unambiguous',
    cacheDirectory: process.env.BABEL_CACHE !== 'none',
    // enable by default
    babelrc: !!process.env.BABELRC,
    // disable by default
    customize: require.resolve('babel-preset-umi/lib/webpack-overrides')
  };
  const babel = opts.babel || {};

  const babelOpts = _objectSpread({
    presets: [...(babel.presets || []), ...(opts.extraBabelPresets || [])],
    plugins: [...(babel.plugins || []), ...(opts.extraBabelPlugins || []), [require.resolve('babel-plugin-named-asset-import'), {
      loaderMap: {
        svg: {
          ReactComponent: `${require.resolve('../svgr')}?-prettier,-svgo![path]`
        }
      }
    }]]
  }, babelOptsCommon);

  if (opts.disableDynamicImport) {
    babelOpts.plugins = [...(babelOpts.plugins || []), require.resolve('babel-plugin-dynamic-import-node')];
  } // module -> eslint


  if (process.env.ESLINT && process.env.ESLINT !== 'none') {
    require('./eslint').default(webpackConfig, opts);
  } // Avoid "require is not defined" errors


  webpackConfig.module.rule('mjs-require').test(/\.mjs$/).type('javascript/auto').include.add(opts.cwd); // module -> mjs

  webpackConfig.module.rule('mjs').test(/\.mjs$/).include.add(opts.cwd).end().use('babel-loader').loader(require.resolve('babel-loader')).options(babelOpts); // module -> js

  webpackConfig.module.rule('js').test(/\.js$/).include.add(opts.cwd).end().exclude.add(/node_modules/).end().use('babel-loader').loader(require.resolve('babel-loader')).options(babelOpts); // module -> jsx
  // jsx 不 exclude node_modules

  webpackConfig.module.rule('jsx').test(/\.jsx$/).include.add(opts.cwd).end().use('babel-loader').loader(require.resolve('babel-loader')).options(babelOpts); // module -> extraBabelIncludes
  // suport es5ImcompatibleVersions

  const extraBabelIncludes = (opts.extraBabelIncludes || []).concat(a => {
    if (!a.includes('node_modules')) return false;
    const pkgPath = (0, _es5ImcompatibleVersions.getPkgPath)(a);
    return (0, _es5ImcompatibleVersions.shouldTransform)(pkgPath);
  });
  extraBabelIncludes.forEach((include, index) => {
    const rule = `extraBabelInclude_${index}`;
    webpackConfig.module.rule(rule).test(/\.jsx?$/).include.add(include).end().use('babel-loader').loader(require.resolve('babel-loader')).options(babelOpts);
  }); // module -> tsx?

  const tsConfigFile = opts.tsConfigFile || ((0, _fs().existsSync)((0, _path().join)(opts.cwd, 'tsconfig.json')) ? (0, _path().join)(opts.cwd, 'tsconfig.json') : (0, _path().join)(__dirname, 'tsconfig.default.json'));
  webpackConfig.module.rule('ts').test(/\.tsx?$/).use('babel-loader').loader(require.resolve('babel-loader')).options(babelOpts).end().use('ts-loader').loader(require.resolve('ts-loader')).options(_objectSpread({
    configFile: tsConfigFile,
    transpileOnly: true,

    // ref: https://github.com/TypeStrong/ts-loader/blob/fbed24b/src/utils.ts#L23
    errorFormatter(error, colors) {
      const messageColor = error.severity === 'warning' ? colors.bold.yellow : colors.bold.red;
      return colors.grey('[tsl] ') + messageColor(error.severity.toUpperCase()) + (error.file === '' ? '' : messageColor(' in ') + colors.bold.cyan(`${(0, _path().relative)(cwd, (0, _path().join)(error.context, error.file))}(${error.line},${error.character})`)) + _os().EOL + messageColor(`      TS${error.code}: ${error.content}`);
    }

  }, opts.typescript || {})); // module -> gql, graphql

  webpackConfig.module.rule('graphql').test(/\.(graphql|gql)$/).exclude.add(/node_modules/).end().use('graphql-tag-loader').loader('graphql-tag/loader'); // module -> css

  require('./css').default(webpackConfig, opts); // plugins -> define


  webpackConfig.plugin('define').use(require('webpack/lib/DefinePlugin'), [(0, _resolveDefine.default)(opts)]); // plugins -> progress bar

  const NO_PROGRESS = process.env.PROGRESS === 'none';

  if (!process.env.__FROM_UMI_TEST) {
    if (!process.env.CI && !NO_PROGRESS) {
      if (process.platform === 'win32') {
        webpackConfig.plugin('progress').use(require('progress-bar-webpack-plugin'));
      } else {
        webpackConfig.plugin('progress').use(require('webpackbar'), [{
          color: 'green',
          reporters: ['fancy']
        }]);
      }
    }
  } // 没用到，先注释了。
  // plugins -> progress report
  // webpackConfig.plugin('progressReport').use(ProgressPlugin, [
  //   percentage => {
  //     send({
  //       type: STARTING,
  //       progress: {
  //         percentage,
  //       },
  //     });
  //   },
  // ]);
  // plugins -> ignore moment locale


  if (opts.ignoreMomentLocale) {
    webpackConfig.plugin('ignore-moment-locale').use(require('webpack/lib/IgnorePlugin'), [/^\.\/locale$/, /moment$/]);
  } // plugins -> analyze


  if (process.env.ANALYZE && !opts.ssr || process.env.ANALYZE_SSR && opts.ssr) {
    webpackConfig.plugin('bundle-analyzer').use(require('umi-webpack-bundle-analyzer').BundleAnalyzerPlugin, [{
      analyzerMode: process.env.ANALYZE_MODE || 'server',
      analyzerPort: process.env.ANALYZE_PORT || 8888,
      openAnalyzer: process.env.ANALYZE_OPEN !== 'none',
      // generate stats file while ANALYZE_DUMP exist
      generateStatsFile: !!process.env.ANALYZE_DUMP,
      statsFilename: process.env.ANALYZE_DUMP || 'stats.json',
      logLevel: process.env.ANALYZE_LOG_LEVEL || 'info',
      defaultSizes: 'parsed' // stat  // gzip

    }]);
  } // plugins -> analyze report


  if (process.env.ANALYZE_REPORT) {
    webpackConfig.plugin('bundle-analyzer-reporter').use(require('umi-webpack-bundle-analyzer').BundleAnalyzerPlugin, [{
      analyzerMode: 'disabled',
      // 关闭 analyzer server
      generateReportFile: true,
      // 开启报告生成功能
      reportDepth: 2,
      // 裁剪深度 2
      reportDir: process.cwd(),
      statsFilename: process.env.ANALYZE_DUMP || 'bundlestats.json' // 默认生成到 bundlestats.json

    }]);
  }

  if (process.env.DUPLICATE_CHECKER) {
    webpackConfig.plugin('duplicate-package-checker').use(require('duplicate-package-checker-webpack-plugin'));
  }

  if (process.env.FORK_TS_CHECKER) {
    webpackConfig.plugin('fork-ts-checker').use(require('fork-ts-checker-webpack-plugin'), [{
      formatter: 'codeframe'
    }]);
  } // plugins -> copy


  if ((0, _fs().existsSync)((0, _path().join)(opts.cwd, 'public'))) {
    webpackConfig.plugin('copy-public').use(require('copy-webpack-plugin'), [[{
      from: (0, _path().join)(opts.cwd, 'public'),
      to: absOutputPath,
      toType: 'dir'
    }]]);
  }

  if (opts.copy) {
    makeArray(opts.copy).forEach((copy, index) => {
      if (typeof copy === 'string') {
        copy = {
          from: (0, _path().join)(opts.cwd, copy),
          to: absOutputPath
        };
      }

      webpackConfig.plugin(`copy-${index}`).use(require('copy-webpack-plugin'), [[copy]]);
    });
  }

  if (!process.env.__FROM_UMI_TEST) {
    // filter `Conflicting order between` warning
    webpackConfig.plugin('filter-css-conflicting-warnings').use(require('./FilterCSSConflictingWarning').default); // plugins -> friendly-errors

    const _process$env$CLEAR_CO = process.env.CLEAR_CONSOLE,
          CLEAR_CONSOLE = _process$env$CLEAR_CO === void 0 ? 'none' : _process$env$CLEAR_CO;
    webpackConfig.plugin('friendly-errors').use(require('friendly-errors-webpack-plugin'), [{
      clearConsole: CLEAR_CONSOLE !== 'none'
    }]);
  } // externals


  if (opts.externals) {
    webpackConfig.externals(opts.externals);
  } // node


  webpackConfig.node.merge({
    setImmediate: false,
    process: 'mock',
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  });

  if (isDev) {
    require('./dev').default(webpackConfig, opts);
  } else {
    require('./prod').default(webpackConfig, opts);
  }

  if (opts.chainConfig) {
    (0, _assert().default)(typeof opts.chainConfig === 'function', `opts.chainConfig should be function, but got ${opts.chainConfig}`);
    opts.chainConfig(webpackConfig);
  }

  let config = webpackConfig.toConfig();

  if (process.env.SPEED_MEASURE && !opts.ssr) {
    const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');

    const smpOption = process.env.SPEED_MEASURE === 'CONSOLE' ? {
      outputFormat: 'human',
      outputTarget: console.log
    } : {
      outputFormat: 'json',
      outputTarget: (0, _path().join)(process.cwd(), 'speed-measure.json')
    };
    const smp = new SpeedMeasurePlugin(smpOption);
    config = smp.wrap(config);
  }

  return config;
}