"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getConfig; var _webpack = _interopRequireDefault(require("webpack")); var _caseSensitivePathsWebpackPlugin = _interopRequireDefault(require("case-sensitive-paths-webpack-plugin")); var _systemBellWebpackPlugin = _interopRequireDefault(require("system-bell-webpack-plugin")); var _extractTextWebpackPlugin = _interopRequireDefault(require("extract-text-webpack-plugin")); var _webpackManifestPlugin = _interopRequireDefault(require("webpack-manifest-plugin")); var _swPrecacheWebpackPlugin = _interopRequireDefault(require("sw-precache-webpack-plugin")); var _autoprefixer = _interopRequireDefault(require("autoprefixer")); var _path = require("path"); var _fs = require("fs"); var _eslintFormatter = _interopRequireDefault(require("react-dev-utils/eslintFormatter")); var _assert = _interopRequireDefault(require("assert")); var _deprecate = _interopRequireDefault(require("deprecate")); var _webpackBundleAnalyzer = require("webpack-bundle-analyzer"); var _copyWebpackPlugin = _interopRequireDefault(require("copy-webpack-plugin")); var _htmlWebpackPlugin = _interopRequireDefault(require("html-webpack-plugin")); var _progressBarWebpackPlugin = _interopRequireDefault(require("progress-bar-webpack-plugin")); var _resolve = require("resolve"); var _forkTsCheckerWebpackPlugin = _interopRequireDefault(require("fork-ts-checker-webpack-plugin")); var _hardSourceWebpackPlugin = _interopRequireDefault(require("hard-source-webpack-plugin")); var _uglifyJS = _interopRequireDefault(require("./defaultConfigs/uglifyJS")); var _babel = _interopRequireDefault(require("./defaultConfigs/babel")); var _browsers = _interopRequireDefault(require("./defaultConfigs/browsers")); var _stringifyObject = _interopRequireDefault(require("./stringifyObject")); var _normalizeTheme = _interopRequireDefault(require("./normalizeTheme")); var _applyWebpackConfig = require("./applyWebpackConfig"); var _readRc = _interopRequireDefault(require("./readRc")); var _utils = require("./utils"); var _es5ImcompatibleVersions = require("./es5ImcompatibleVersions"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, 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; } const _require = require('awesome-typescript-loader'), TsConfigPathsPlugin = _require.TsConfigPathsPlugin; // eslint-disable-line const debug = require('debug')('af-webpack:getConfig'); if (process.env.DISABLE_TSLINT) { (0, _deprecate.default)('DISABLE_TSLINT is deprecated, use TSLINT=none instead'); } if (process.env.DISABLE_ESLINT) { (0, _deprecate.default)('DISABLE_ESLINT is deprecated, use ESLINT=none instead'); } if (process.env.NO_COMPRESS) { (0, _deprecate.default)('NO_COMPRESS is deprecated, use COMPRESS=none instead'); } function getConfig(opts = {}) { (0, _assert.default)(opts.cwd, 'opts.cwd must be specified'); const isDev = process.env.NODE_ENV === 'development'; const theme = (0, _normalizeTheme.default)(opts.theme); const postcssOptions = { // Necessary for external CSS imports to work // https://github.com/facebookincubator/create-react-app/issues/2677 ident: 'postcss', plugins: () => [require('postcss-flexbugs-fixes'), // eslint-disable-line (0, _autoprefixer.default)({ browsers: opts.browserslist || _browsers.default, flexbox: 'no-2009' }), ...(opts.extraPostCSSPlugins ? opts.extraPostCSSPlugins : [])] }; const cssModulesConfig = { modules: true, localIdentName: isDev ? '[name]__[local]___[hash:base64:5]' : '[local]___[hash:base64:5]' }; const lessOptions = _objectSpread({ modifyVars: theme }, opts.lessLoaderOptions || {}); const cssOptions = _objectSpread({ importLoaders: 1 }, isDev ? {} : { minimize: !(process.env.CSS_COMPRESS === 'none' || process.env.COMPRESS === 'none' || process.env.NO_COMPRESS) ? { // ref: https://github.com/umijs/umi/issues/164 minifyFontValues: false } : false, sourceMap: !opts.disableCSSSourceMap }, opts.cssLoaderOptions || {}); function getCSSLoader(opts = {}) { const cssModules = opts.cssModules, less = opts.less, sass = opts.sass, sassOptions = opts.sassOptions; let hasSassLoader = true; try { require.resolve('sass-loader'); } catch (e) { hasSassLoader = false; } return [require.resolve('style-loader'), { loader: require.resolve('css-loader'), options: _objectSpread({}, cssOptions, cssModules ? cssModulesConfig : {}) }, { loader: require.resolve('postcss-loader'), options: postcssOptions }, ...(less ? [{ loader: require.resolve('less-loader'), options: lessOptions }] : []), ...(sass && hasSassLoader ? [{ loader: require.resolve('sass-loader'), options: sassOptions }] : [])]; } function exclude(filePath) { if (/node_modules/.test(filePath)) { return true; } if (opts.cssModulesWithAffix) { if (/\.module\.(css|less|sass|scss)$/.test(filePath)) return true; } if (opts.cssModulesExcludes) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = opts.cssModulesExcludes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { const exclude = _step.value; if (filePath.indexOf(exclude) > -1) return true; } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } } const cssRules = [...(opts.cssModulesExcludes ? opts.cssModulesExcludes.map(file => { return { test(filePath) { return filePath.indexOf(file) > -1; }, use: getCSSLoader({ less: (0, _path.extname)(file).toLowerCase() === '.less', sass: (0, _path.extname)(file).toLowerCase() === '.sass' || (0, _path.extname)(file).toLowerCase() === '.scss', sassOptions: opts.sass }) }; }) : []), ...(opts.cssModulesWithAffix ? [{ test: /\.module\.css$/, use: getCSSLoader({ cssModules: true }) }, { test: /\.module\.less$/, use: getCSSLoader({ cssModules: true, less: true }) }, { test: /\.module\.(sass|scss)$/, use: getCSSLoader({ cssModules: true, sass: true, sassOptions: opts.sass }) }] : []), { test: /\.css$/, exclude, use: getCSSLoader({ cssModules: !opts.disableCSSModules }) }, { test: /\.css$/, include: /node_modules/, use: getCSSLoader() }, { test: /\.less$/, exclude, use: getCSSLoader({ cssModules: !opts.disableCSSModules, less: true }) }, { test: /\.less$/, include: /node_modules/, use: getCSSLoader({ less: true }) }, { test: /\.(sass|scss)$/, exclude, use: getCSSLoader({ cssModules: !opts.disableCSSModules, sass: true, sassOptions: opts.sass }) }, { test: /\.(sass|scss)$/, include: /node_modules/, use: getCSSLoader({ sass: true, sassOptions: opts.sass }) }]; // 生成环境下用 ExtractTextPlugin 提取出来 if (!isDev) { cssRules.forEach(rule => { rule.use = _extractTextWebpackPlugin.default.extract({ use: rule.use.slice(1) }); }); } // TODO: 根据 opts.hash 自动处理这里的 filename const commonsPlugins = (opts.commons || []).map(common => { return new _webpack.default.optimize.CommonsChunkPlugin(common); }); // Declare outputPath here for reuse const outputPath = opts.outputPath ? (0, _path.resolve)(opts.cwd, opts.outputPath) : (0, _path.resolve)(opts.cwd, 'dist'); // Copy files in public to outputPath const copyPlugins = opts.copy ? [new _copyWebpackPlugin.default(opts.copy)] : []; if ((0, _fs.existsSync)((0, _path.resolve)(opts.cwd, 'public'))) { copyPlugins.push(new _copyWebpackPlugin.default([{ from: (0, _path.resolve)(opts.cwd, 'public'), to: outputPath, toType: 'dir' }], { ignore: ['**/.*'] })); } // js 和 css 采用不同的 hash 算法 const jsHash = !isDev && opts.hash ? '.[chunkhash:8]' : ''; const cssHash = !isDev && opts.hash ? '.[contenthash:8]' : ''; const babelOptions = _objectSpread({}, opts.babel || _babel.default, { cacheDirectory: process.env.BABEL_CACHE !== 'none', babelrc: !!process.env.BABELRC }); babelOptions.plugins = [...(babelOptions.plugins || []), ...(opts.disableDynamicImport ? [require.resolve('babel-plugin-dynamic-import-node-sync')] : [])]; const babelUse = [{ loader: require('path').join(__dirname, 'debugLoader.js') // eslint-disable-line }, { loader: require.resolve('babel-loader'), options: babelOptions }]; const babelOptionsDeps = { presets: [[require.resolve('babel-preset-umi'), { disableTransform: true }]], cacheDirectory: process.env.BABEL_CACHE !== 'none', babelrc: !!process.env.BABELRC }; const babelUseDeps = [{ loader: require('path').join(__dirname, 'debugLoader.js') // eslint-disable-line }, { loader: require.resolve('babel-loader'), options: babelOptionsDeps }]; const eslintOptions = { formatter: _eslintFormatter.default, baseConfig: { extends: [require.resolve('eslint-config-umi')] }, ignore: false, eslintPath: require.resolve('eslint'), useEslintrc: false }; // 用用户的 eslint try { const _require2 = require((0, _path.resolve)('package.json')), dependencies = _require2.dependencies, devDependencies = _require2.devDependencies; // eslint-disable-line if (dependencies.eslint || devDependencies.eslint) { const eslintPath = (0, _resolve.sync)('eslint', { basedir: opts.cwd }); eslintOptions.eslintPath = eslintPath; debug(`use user's eslint bin: ${eslintPath}`); } } catch (e) {} // do nothing // 读用户的 eslintrc const userEslintRulePath = (0, _path.resolve)(opts.cwd, '.eslintrc'); if ((0, _fs.existsSync)(userEslintRulePath)) { try { const userRc = (0, _readRc.default)(userEslintRulePath); debug(`userRc: ${JSON.stringify(userRc)}`); if (userRc.extends) { debug(`use user's .eslintrc: ${userEslintRulePath}`); eslintOptions.useEslintrc = true; eslintOptions.baseConfig = false; eslintOptions.ignore = true; } else { debug(`extend with user's .eslintrc: ${userEslintRulePath}`); eslintOptions.baseConfig = _objectSpread({}, eslintOptions.baseConfig, userRc); } } catch (e) { debug(e); } } const extraBabelIncludes = opts.extraBabelIncludes || []; if (opts.es5ImcompatibleVersions) { extraBabelIncludes.push(a => { if (a.indexOf('node_modules') === -1) return false; const pkgPath = (0, _es5ImcompatibleVersions.getPkgPath)(a); return (0, _es5ImcompatibleVersions.shouldTransform)(pkgPath); }); } const config = { bail: !isDev, devtool: opts.devtool || undefined, entry: opts.entry || null, output: { path: outputPath, // Add /* filename */ comments to generated require()s in the output. pathinfo: isDev, filename: `[name]${jsHash}.js`, publicPath: opts.publicPath || undefined, chunkFilename: `[name]${jsHash}.async.js` }, resolve: { modules: ['node_modules', (0, _path.resolve)(__dirname, '../node_modules'), ...(opts.extraResolveModules || [])], extensions: [...(opts.extraResolveExtensions || []), '.web.js', '.web.jsx', '.web.ts', '.web.tsx', '.js', '.json', '.jsx', '.ts', '.tsx'], alias: _objectSpread({}, opts.alias), plugins: process.env.TS_CONFIG_PATHS_PLUGIN && process.env.TS_CONFIG_PATHS_PLUGIN !== 'none' ? [new TsConfigPathsPlugin()] : [] }, module: { rules: [...(process.env.DISABLE_TSLINT || process.env.TSLINT === 'none' ? [] : [{ test: /\.tsx?$/, include: opts.cwd, exclude: /node_modules/, enforce: 'pre', use: [{ options: { emitErrors: true // formatter: eslintFormatter, }, loader: require.resolve('tslint-loader') }] }]), ...(process.env.DISABLE_ESLINT || process.env.ESLINT === 'none' ? [] : [{ test: /\.(js|jsx)$/, include: opts.cwd, exclude: /node_modules/, enforce: 'pre', use: [{ options: eslintOptions, loader: require.resolve('eslint-loader') }] }]), { exclude: [/\.(html|ejs)$/, /\.json$/, /\.(js|jsx|ts|tsx)$/, /\.(css|less|scss|sass)$/, ...(opts.urlLoaderExcludes || [])], loader: require.resolve('url-loader'), options: { limit: 10000, name: 'static/[name].[hash:8].[ext]' } }, { test: /\.js$/, include: opts.cwd, exclude: /node_modules/, use: babelUse }, { test: /\.jsx$/, include: opts.cwd, use: babelUse }, { test: /\.(ts|tsx)$/, include: opts.cwd, exclude: /node_modules/, use: [...babelUse, { loader: require.resolve('awesome-typescript-loader'), options: _objectSpread({ configFileName: opts.tsConfigFile || (0, _path.join)(opts.cwd, 'tsconfig.json'), transpileOnly: true }, opts.typescript || {}) }] }, ...extraBabelIncludes.map(include => { return { test: /\.(js|jsx)$/, include: typeof include === 'string' ? (0, _path.join)(opts.cwd, include) : include, use: babelUseDeps }; }), { test: /\.html$/, loader: require.resolve('file-loader'), options: { name: '[name].[ext]' } }, ...cssRules] }, plugins: [...(isDev ? [new _webpack.default.HotModuleReplacementPlugin(), // Disable this plugin since it causes 100% cpu when have lost deps // new WatchMissingNodeModulesPlugin(join(opts.cwd, 'node_modules')), new _systemBellWebpackPlugin.default(), ...(process.env.HARD_SOURCE && process.env.HARD_SOURCE !== 'none' ? [new _hardSourceWebpackPlugin.default()] : [])].concat(opts.devtool ? [] : [new _webpack.default.SourceMapDevToolPlugin({ columns: false, moduleFilenameTemplate: info => { if (/\/koi-pkgs\/packages/.test(info.absoluteResourcePath) || /packages\/koi-core/.test(info.absoluteResourcePath) || /webpack\/bootstrap/.test(info.absoluteResourcePath) || /\/node_modules\//.test(info.absoluteResourcePath)) { return `internal:///${info.absoluteResourcePath}`; } return (0, _path.resolve)(info.absoluteResourcePath).replace(/\\/g, '/'); } })]) : [...(process.env.__FROM_TEST ? [] : [new _webpack.default.HashedModuleIdsPlugin()]), new _webpack.default.optimize.ModuleConcatenationPlugin(), new _extractTextWebpackPlugin.default({ filename: `[name]${cssHash}.css`, allChunks: true }), ...(opts.serviceworker ? [new _swPrecacheWebpackPlugin.default(_objectSpread({ filename: 'service-worker.js', minify: !(process.env.NO_COMPRESS || process.env.COMPRESS === 'none'), staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/] }, opts.serviceworker))] : []), ...(opts.manifest ? [new _webpackManifestPlugin.default(_objectSpread({ fileName: 'manifest.json' }, opts.manifest))] : [])]), ...(isDev || process.env.NO_COMPRESS || process.env.COMPRESS === 'none' ? [] : [new _webpack.default.optimize.UglifyJsPlugin(_objectSpread({}, _uglifyJS.default, opts.devtool ? { sourceMap: true } : {}))]), new _webpack.default.DefinePlugin(_objectSpread({ 'process.env.NODE_ENV': JSON.stringify( // eslint-disable-line isDev ? 'development' : 'production'), // eslint-disable-line 'process.env.HMR': process.env.HMR }, process.env.SOCKET_SERVER ? { 'process.env.SOCKET_SERVER': JSON.stringify(process.env.SOCKET_SERVER) } : {}, (0, _stringifyObject.default)(opts.define || {}))), ...(opts.html ? [new _htmlWebpackPlugin.default(opts.html)] : []), new _caseSensitivePathsWebpackPlugin.default(), new _webpack.default.LoaderOptionsPlugin({ options: { context: __dirname } }), new _progressBarWebpackPlugin.default(), ...(process.env.TS_TYPECHECK ? [new _forkTsCheckerWebpackPlugin.default()] : []), ...(opts.ignoreMomentLocale ? [new _webpack.default.IgnorePlugin(/^\.\/locale$/, /moment$/)] : []), ...commonsPlugins, ...copyPlugins, ...(process.env.ANALYZE ? [new _webpackBundleAnalyzer.BundleAnalyzerPlugin({ analyzerMode: 'server', analyzerPort: process.env.ANALYZE_PORT || 8888, openAnalyzer: true })] : [])], externals: opts.externals, node: { dgram: 'empty', fs: 'empty', net: 'empty', tls: 'empty', child_process: 'empty' }, performance: isDev ? { hints: false } : {} }; if (process.env.PUBLIC_PATH) { config.output.publicPath = `${(0, _utils.stripLastSlash)(process.env.PUBLIC_PATH)}/`; } return (0, _applyWebpackConfig.applyWebpackConfig)(opts.cwd, config); }