UNPKG

@cisdi/pangu

Version:

develop tool for ui-engine project

333 lines (313 loc) 8.42 kB
const path = require('path') const fs = require('fs') const webpack = require('webpack') const MiniCSSExtractPlugin = require('mini-css-extract-plugin') const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin') // const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') const TerserWebpackPlugin = require('terser-webpack-plugin') const WebpackBar = require('webpackbar') const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin') const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin') // const typescriptFormatter = require('react-dev-utils/typescriptFormatter') // const WebpackManifestPlugin = require('webpack-manifest-plugin') const WorkboxWebpackPlugin = require('workbox-webpack-plugin') // const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin') const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') const CopyWebpackPlugin = require('copy-webpack-plugin') const FaviconsWebpackPlugin = require('favicons-webpack-plugin') const ESLintPlugin = require('eslint-webpack-plugin') // const AntDesignThemePlugin = require('antd-theme-webpack-plugin') // const { getLessVars } = require('antd-theme-generator') const { argv } = require('yargs') const postcssConfig = require('../postcss.config') const { srcDir, workDir, outputDir, publicDir, publicPath, tsConfigPath, } = require('../../utils/paths') const app = require('../../utils/app') const theme = require('../../utils/theme') const globalsConfig = require('../globals.config') const { findEntryPath } = require('../../utils/entry') const PRODUCT = process.env.NODE_ENV === 'production' const DEV = process.env.NODE_ENV === 'development' const entry = findEntryPath() // generate css loader for specific lang function getCSSLoader(lang, modules) { let loaders = [] if (DEV) { loaders = [ { loader: require.resolve('style-loader'), }, ] } else { loaders = [MiniCSSExtractPlugin.loader] } // typescript 模式下开启 if (fs.existsSync(tsConfigPath)) { loaders.push('@opd/css-modules-typings-loader') } loaders = [ ...loaders, { loader: 'css-loader', options: { importLoaders: lang === 'css' ? 1 : 2, sourceMap: true, modules: { localIdentName: DEV ? '[path][name]__[local]' : '[hash:base64]', exportLocalsConvention: 'camelCaseOnly', auto: true, }, }, }, { loader: 'postcss-loader', options: { sourceMap: true, postcssOptions: { ...postcssConfig, config: true, }, }, }, ] if (lang === 'less') { loaders.push({ loader: 'less-loader', options: { sourceMap: true, lessOptions: { javascriptEnabled: true, modifyVars: theme || {}, }, }, }) } return loaders } const config = { mode: PRODUCT ? 'production' : 'development', entry: { app: PRODUCT ? [entry] : [ require.resolve('react-dev-utils/webpackHotDevClient'), // for HMR entry, ], }, output: { publicPath, path: outputDir, filename: PRODUCT ? '[name].[contenthash].js' : '[name].js', chunkFilename: PRODUCT ? '[id].[contenthash].js' : '[id].js', }, resolve: { modules: ['node_modules'], extensions: ['.ts', '.tsx', '.js', '.jsx', '.json', '.css', '.less'], mainFields: ['module', 'main'], alias: { '@': srcDir, }, }, devtool: DEV && 'cheap-module-eval-source-map', module: { rules: [ { test: /\.(j|t)sx?$/, include: [srcDir], exclude: /node_modules/, use: [ { loader: 'thread-loader', }, { loader: 'babel-loader', options: { cacheDirectory: true, }, }, ], }, { test: /.css$/, use: getCSSLoader('css'), }, { test: /.less$/, use: getCSSLoader('less'), }, { test: /\.(eot|ttf|woff|woff2)$/, loader: 'url-loader', options: { limit: 10000, name: '[name].[hash:8].[ext]', }, }, { test: /\.(png|jpg|gif|svg)$/, loader: 'url-loader', options: { limit: 10000, name: '[name].[hash:8].[ext]', }, }, ], }, plugins: [ new WebpackBar({ name: 'Pangu', minimal: true, compiledIn: true, }), new webpack.WatchIgnorePlugin([/(css|less)\.d\.ts$/]), new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), new webpack.DefinePlugin(globalsConfig), new ModuleNotFoundPlugin(), // new WebpackManifestPlugin({ // fileName: 'asset-manifest.json', // generate: (seed, files, entrypoints) => { // const manifestFiles = files.reduce((manifest, file) => { // manifest[file.name] = file.path // return manifest // }, seed) // const entrypointFiles = [] // Object.entries(entrypoints).forEach(([key, files]) => // files.forEach((fileName) => { // if (!fileName.endsWith('.map')) { // entrypointFiles.push(fileName) // } // }) // ) // return { // files: manifestFiles, // entrypoints: entrypointFiles, // } // }, // }), new webpack.LoaderOptionsPlugin({ debug: true, options: { context: __dirname, }, }), // new FriendlyErrorsPlugin(), new MiniCSSExtractPlugin({ ignoreOrder: true, filename: '[name].[contenthash].css', chunkFilename: '[id].[contenthash].css', }), ], optimization: { minimize: PRODUCT, minimizer: [ new TerserWebpackPlugin({ cache: true, parallel: true, sourceMap: true, // set to true if you want JS source maps }), new OptimizeCSSAssetsPlugin({ cssProcessorOptions: { map: { inline: false, }, }, }), ], splitChunks: { chunks: 'all', }, runtimeChunk: true, }, } if (app.logo && fs.existsSync(path.resolve(workDir, app.logo))) { config.plugins.push( new FaviconsWebpackPlugin({ logo: path.resolve(workDir, app.logo), cache: true, prefix: 'icons', inject: true, favicons: { appName: app.appName, icons: { favicons: true, android: true, appleIcon: true, appleStartup: true, firefox: true, windows: true, coast: false, yandex: false, }, }, }) ) } if (DEV) { config.plugins.push(new webpack.HotModuleReplacementPlugin()) config.plugins.push( new WatchMissingNodeModulesPlugin(path.resolve(workDir, 'node_modules')) ) config.plugins.push( new ESLintPlugin({ extensions: ['js', 'ts', 'jsx', 'tsx', 'vue'], fix: true, lintDirtyModulesOnly: true, }) ) } if (PRODUCT) { config.plugins.push( new WorkboxWebpackPlugin.GenerateSW({ clientsClaim: true, exclude: [/\.map$/, /asset-manifest\.json$/], // navigateFallback: 'index.html', // navigateFallbackBlacklist: [ // // Exclude URLs starting with /_, as they're likely an API call // new RegExp('^/_'), // // Exclude URLs containing a dot, as they're likely a resource in // // public/ and not a SPA route // new RegExp('/[^/]+\\.[^/]+$'), // ], }) ) const hasPublicDir = fs.existsSync(publicDir) if (hasPublicDir) { config.plugins.push( new CopyWebpackPlugin({ patterns: [ { from: publicDir, to: outputDir, noErrorOnMissing: true, globOptions: { ignore: ['**/*.ejs', '**/*.md'], }, }, ], }) ) } if (argv.ana) { // bundle analyzer config.plugins.push( new BundleAnalyzerPlugin({ // generateStatsFile: true }) ) } // config.optimization.splitChunks.cacheGroups = { // styles: { // name: 'styles', // test: /\.css$/, // chunks: 'all', // enforce: true // } // } } module.exports = config