sorrycc / example-webpack-mfsu

Start the antd + framer-motion project without cache in one second.
82 stars 9 forks source link

error - TypeError: Cannot set properties of undefined (setting 'entry') #2

Open X-neuron opened 2 years ago

X-neuron commented 2 years ago
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const resolve = require('resolve');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const Webpackbar = require('webpackbar');

const CopyPlugin = require('copy-webpack-plugin');
const CircularDependencyPlugin = require('circular-dependency-plugin');

const PnpWebpackPlugin = require('pnp-webpack-plugin');

const TerserPlugin = require('terser-webpack-plugin');
// const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const SafePostCssParser = require('postcss-safe-parser');
const postcssNormalize = require('postcss-normalize');
// const { CleanWebpackPlugin } = require("clean-webpack-plugin");
// const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
// const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');

const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');

const paths = require('./paths');
const modules = require('./modules');
const getClientEnvironment = require('./env');

const { MFSU } = require('@umijs/mfsu');
const mfsu = new MFSU({
  implementor: webpack,
  buildDepWithESBuild: {},
});

// Check if TypeScript is setup
const useTypeScript = fs.existsSync(paths.appTsConfig);
// Get the path to the uncompiled service worker (if it exists).
const { swSrc } = paths;

const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));

const isEnvDevelopment = env.raw.NODE_ENV === 'development';
const isEnvProduction = env.raw.NODE_ENV === 'production';

const isEnvProductionProfile =
  isEnvProduction && process.argv.includes('--profile');

const getStyleLoaders = (testReg, loader, options) => {
  function applyLoaders(isCSSModules) {
    const loaders = [
      isEnvDevelopment && require.resolve('style-loader'),
      isEnvProduction && {
        loader: MiniCssExtractPlugin.loader,
        // css is located in `static/css`, use '../../' to locate index.html folder
        // in production `paths.publicUrlOrPath` can be a relative path
        options: paths.publicUrlOrPath.startsWith('.')
          ? {
              // publicPath: 'auto',
              hmr: isEnvDevelopment,
            }
          : {},
      },
      {
        loader: require.resolve('css-loader'),
        options: {
          importLoaders: loader ? 1 : 0,
          ...(isCSSModules
            ? {
                modules: {
                  localIdentName: '[local]___[hash:base64:5]',
                },
              }
            : {}),
        },
      },
      {
        loader: 'postcss-loader',
        options: {
          postcssOptions: {
            ident: 'postcss',
            plugins: [
              require('postcss-flexbugs-fixes'),
              require('postcss-preset-env')({
                autoprefixer: {
                  flexbox: 'no-2009',
                },
                stage: 3,
              }),
              postcssNormalize(),
            ],
          },
          sourceMap: isEnvDevelopment,
        },
      },
    ].filter(Boolean);
    if (loader) {
      loaders.push(
        {
          loader: require.resolve(loader),
          options: options || {},
        },
      );
    }
    return loaders;
  }

  return {
    test: testReg,
    oneOf: [
      {
        resourceQuery: /modules/,
        use: applyLoaders(true),
      },
      {
        use: applyLoaders(false),
      },
    ],
  };
};

const config = {
  mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
  devtool: isEnvProduction ? false : 'cheap-module-source-map', //"eval-cheap-module-source-map"

  entry:{
    main: [paths.appSrc + '/index.jsx']
  },

  output: {
    // The build folder.
    path: isEnvProduction ? paths.appBuild : undefined,

    pathinfo: false,
    // There will be one main bundle, and one file per asynchronous chunk.
    // In development, it does not produce real files.
    filename: isEnvProduction
      ? 'static/js/[name].[contenthash:8].js'
      : isEnvDevelopment && 'static/js/bundle.js',

    publicPath: paths.publicUrlOrPath,
    // Point sourcemap entries to original disk location (format as URL on Windows)
    devtoolModuleFilenameTemplate: isEnvProduction
      ? (info) =>
          path
            .relative(paths.appSrc, info.absoluteResourcePath)
            .replace(/\\/g, '/')
      : isEnvDevelopment &&
        ((info) => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),

  },
  resolve: {

    modules: ['node_modules', paths.appNodeModules].concat(
      modules.additionalModulePaths || [],
    ),

    extensions: paths.moduleFileExtensions
      .map((ext) => `.${ext}`)
      .filter((ext) => useTypeScript || !ext.includes('ts')),
    alias: {
      '@': path.resolve(process.cwd(), 'src'),

      'react-native': 'react-native-web',
      // Allows for better profiling with ReactDevTools
      ...(isEnvProductionProfile && {
        'react-dom$': 'react-dom/profiling',
        'scheduler/tracing': 'scheduler/tracing-profiling',
      }),
      ...(modules.webpackAliases || {}),
    },
    // 不能设为 false,因为 tnpm 是通过 link 处理依赖,设为 false tnpm 下会有大量的冗余模块
    symlinks: true,
    mainFields: ['browser', 'module', 'jsnext:main', 'main'],

    plugins: [
      PnpWebpackPlugin,
    ],
  },
  resolveLoader: {
    plugins: [
      // Also related to Plug'n'Play, but this time it tells webpack to load its loaders
      // from the current package.
      PnpWebpackPlugin.moduleLoader(module),
    ],
  },
  optimization: {
    // moduleIds: isEnvDevelopment ? 'named':'deterministic',
    // chunkIds: isEnvDevelopment ? 'named':'deterministic',
    minimize: isEnvProduction,
    removeAvailableModules: isEnvProduction,
    removeEmptyChunks: isEnvProduction,

    moduleIds: 'deterministic',
    chunkIds: 'deterministic',
    mangleExports: 'deterministic',

    usedExports: true,
    minimizer: [
      new TerserPlugin({
        test: /\.js(\?.*)?$/i,
        parallel: !process.env.CI,
        extractComments: false,
        terserOptions: {
          // https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
          parse: {

            ecma: 8,
          },
          compress: {
            ecma: 5,
            warnings: false,
            comparisons: false,

            inline: 2,

            // turn off flags with small gains to speed up minification
            arrows: false,
            collapse_vars: false, // 0.3kb
            comparisons: false,
            computed_props: false,
            hoist_funs: false,
            hoist_props: false,
            hoist_vars: false,
            inline: false,
            loops: false,
            negate_iife: false,
            properties: false,
            reduce_funcs: false,
            reduce_vars: false,
            switches: false,
            toplevel: false,
            typeofs: false,

            // a few flags with noticable gains/speed ratio
            // numbers based on out of the box vendor bundle
            booleans: true, // 0.7kb
            if_return: true, // 0.4kb
            sequences: true, // 0.7kb
            unused: true, // 2.3kb

            // required features to drop conditional branches
            conditionals: true,
            dead_code: true,
            evaluate: true,
          },
          mangle: {
            safari10: true,
          },
          // Added for profiling in devtools
          keep_classnames: isEnvProductionProfile,
          keep_fnames: isEnvProductionProfile,
          output: {
            ecma: 5,
            comments: false,
            // Turned on because emoji and regex is not minified properly using default
            // https://github.com/facebook/create-react-app/issues/2488
            ascii_only: true,
          },
        },
      }),
      new CssMinimizerPlugin(),

      // new OptimizeCssAssetsPlugin({})
    ].filter(Boolean),

    splitChunks: isEnvDevelopment
      ? false
      : {
          chunks: 'async',
          minSize: 30720,
          minChunks: 1,
          maxAsyncRequests: 6,
          maxInitialRequests: 4,
          automaticNameDelimiter: '-',
          cacheGroups: {
            common: {
              name: 'common',
              chunks: 'all',
              priority: -20,
              minChunks: 2,
              reuseExistingChunk: true,
            },
            vendors: {
              name: 'vendors',
              test: /[\\/]node_modules[\\/]/,
              chunks: 'all',
              priority: -10,
            },
            react: {
              name: 'react',
              test: /[\\/]node_modules[\\/](scheduler|react|react-dom|prop-types)/,
              chunks: 'all',
              enforce: true,
            },
            antd: {
              name: 'antd',
              test: /[\\/]node_modules[\\/](@ant-design|antd)[\\/]/,
              chunks: 'all',
            },
          },
        },
  },
  module: {
    strictExportPresence: true,
    rules: [
      { parser: { requireEnsure: false } },
      {
        test: /\.m?js/,
        resolve: {
          fullySpecified: false,
        },
      },
      {
        test: /\.(js|jsx|ts|tsx)$/,
        include: paths.appSrc,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true,
              // See #6846 for context on why cacheCompression is disabled
              cacheCompression: false,
              compact: isEnvProduction,
              presets: [
                [
                  '@babel/preset-react',
                  {
                    runtime: 'automatic',
                  },
                ],
              ],
              plugins: [
                'lodash',
                '@babel/plugin-transform-runtime',
                ...mfsu.getBabelPlugins(),
              ].filter(Boolean),
            },
          },
        ],
      },
      getStyleLoaders(/\.(css)(\?.*)?$/),
      getStyleLoaders(/\.(less)(\?.*)?$/, 'less-loader', {
        sourceMap: isEnvDevelopment,
        lessOptions: {
          javascriptEnabled: true,
        },
      }),
      getStyleLoaders(/\.(scss|sass)(\?.*)?$/, 'sass-loader', {
        sourceMap: isEnvDevelopment,
      }),

      {
        test: /\.(txt|text|md)$/,
        type: 'asset/resource',
      },
      {
        test: /\.(bmp|png|jpe?g|gif|webp|ico|svg|eot|woff|woff2|ttf)(\?.*)?$/,
        type: 'asset/inline',

      },
      {
        test: /\.html$/,
        use: 'html-loader',
      },
      {
        test: /\.(mp4|webm)$/,
        type: 'asset/inline',

      },
      {
        test: [/\.avif$/],
        type: 'asset/inline',

      },
    ],
  },
  [isEnvDevelopment ? 'devServer' : 'ignoreWarnings']: isEnvDevelopment
    ? {
        onBeforeSetupMiddleware(devServer) {
          for (const middleware of mfsu.getMiddlewares()) {
            devServer.app.use(middleware);
          }
        },

      }
    : [],

  stats: {
    assets: false,
    moduleAssets: false,
    runtime: false,
    runtimeModules: false,
    modules: false,
    entrypoints: false,
  },
  experiments: {
    topLevelAwait: true,
  },
  plugins: [
    new Webpackbar(),
    new CircularDependencyPlugin({
      exclude: /a\.js|node_modules/, // exclude node_modules
      failOnError: false, // show a warning when there is a circular dependency
    }),
    new HtmlWebpackPlugin(
      Object.assign(
        {},
        {
          inject: true,
          template: paths.appHtml,
        },
        isEnvProduction
          ? {
              minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeRedundantAttributes: true,
                useShortDoctype: true,
                removeEmptyAttributes: true,
                removeStyleLinkTypeAttributes: true,
                keepClosingSlash: true,
                minifyJS: true,
                minifyCSS: true,
                minifyURLs: true,
              },
            }
          : undefined,
      ),
    ),

    new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),

    new ModuleNotFoundPlugin(paths.appPath),

    new webpack.DefinePlugin(env.stringified),

    isEnvDevelopment && new WatchMissingNodeModulesPlugin(paths.appNodeModules),

    isEnvProduction &&
      new CompressionPlugin({
        algorithm: 'gzip',
        // cache: true,
        // threshold: 10240,
      }),

    new CopyPlugin({
      patterns: [
        { from: paths.appPublic, to: path.join(paths.appBuild, '/public') },
        // { from: path.join(paths.appSrc,"/locales" ), to: path.join(paths.appBuild,"/public/locales" ) },
      ],
      options: {
        concurrency: 100,
      },
    }),

    isEnvProduction &&
      new MiniCssExtractPlugin({
        // Options similar to the same options in webpackOptions.output
        // both options are optional
        filename: 'static/css/[name].[contenthash:8].css',
        chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
        ignoreOrder: true, // Enable to remove warnings about conflicting order
      }),

    isEnvProduction &&
      new WebpackManifestPlugin({
        fileName: 'assert-manifest.json',
        publicPath: paths.publicUrlOrPath,
        generate: (seed, files, entrypoints) => {
          const manifestFiles = files.reduce((manifest, file) => {
            manifest[file.name] = file.path;
            return manifest;
          }, seed);
          const entrypointFiles = entrypoints.main.filter(
            (fileName) => !fileName.endsWith('.map'),
          );

          return {
            files: manifestFiles,
            entrypoints: entrypointFiles,
          };
        },
      }),

    isEnvProduction &&
      new WorkboxWebpackPlugin.GenerateSW({
        clientsClaim: true, // 让浏览器立即 servece worker 被接管
        skipWaiting: true, // 更新 sw 文件后,立即插队到最前面
        dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
        exclude: [/\.map$/, /assert-manifest\.json$/, /LICENSE/],
        // importWorkboxFrom: 'cdn',
        navigateFallback: `${paths.publicUrlOrPath}index.html`,
        navigateFallbackDenylist: [
          // Exclude URLs starting with /_, as they're likely an API call
          new RegExp('^/_'),
          // Exclude any URLs whose last part seems to be a file extension
          // as they're likely a resource and not a SPA route.
          // URLs containing a "?" character won't be blacklisted as they're likely
          // a route with query params (e.g. auth callbacks).
          new RegExp('/[^/?]+\\.[^/]+$'),
        ],
        // Bump up the default maximum size (2mb) that's precached,
        // to make lazy-loading failure scenarios less likely.
        // See https://github.com/cra-template/pwa/issues/13#issuecomment-722667270
        maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
      }),

    // TypeScript type checking
    useTypeScript &&
      new ForkTsCheckerWebpackPlugin({
        typescript: resolve.sync('typescript', {
          basedir: paths.appNodeModules,
        }),
        async: isEnvDevelopment,
        checkSyntacticErrors: true,
        resolveModuleNameModule: process.versions.pnp
          ? `${__dirname}/pnpTs.js`
          : undefined,
        resolveTypeReferenceDirectiveModule: process.versions.pnp
          ? `${__dirname}/pnpTs.js`
          : undefined,
        tsconfig: paths.appTsConfig,
        reportFiles: [
          // This one is specifically to match during CI tests,
          // as micromatch doesn't match
          // '../cra-template-typescript/template/src/App.tsx'
          // otherwise.
          '../**/src/**/*.{ts,tsx}',
          '**/src/**/*.{ts,tsx}',
          '!**/src/**/__tests__/**',
          '!**/src/**/?(*.)(spec|test).*',
          '!**/src/setupProxy.*',
          '!**/src/setupTests.*',
        ],
        silent: true,
        // The formatter is invoked directly in WebpackDevServerUtils during development
        formatter: isEnvProduction ? typescriptFormatter : undefined,
      }),

  ].filter(Boolean),

  // Turn off performance processing because we utilize
  // our own hints via the FileSizeReporter
  performance: false,
};

mfsu.setWebpackConfig({
  config,
});

module.exports = config;

该配置,我确信入口指向的./src/index.jsx 正确,执行卡在:http://localhost:8080/mf-va_remoteEntry.js 该地址的获取上。

✔ Webpack Compiled successfully in 22.77s

[webpack-dev-server] Project is running at: [webpack-dev-server] Loopback: http://localhost:8080/ [webpack-dev-server] On Your Network (IPv4): http://192.168.18.5:8080/ [webpack-dev-server] On Your Network (IPv6): http://[fe80::e88f:90d2:ae93:e0a6]:8080/ [webpack-dev-server] Content not from webpack is served from 'D:\WebTest\antdfront2-git\public' directory [webpack-dev-middleware] wait until bundle finished: / webpack 5.64.1 compiled successfully in 22785 ms error - TypeError: Cannot set properties of undefined (setting 'entry') at DepBuilder.getWebpackConfig (D:\WebTest\antdfront2-git\node_modules\@umijs\mfsu\dist\depBuilder\depBuilder.js:78:25) at DepBuilder. (D:\WebTest\antdfront2-git\node_modules\@umijs\mfsu\dist\depBuilder\depBuilder.js:28:33) at Generator.next () at fulfilled (D:\WebTest\antdfront2-git\node_modules\@umijs\mfsu\dist\depBuilder\depBuilder.js:5:58)
at processTicksAndRejections (node:internal/process/task_queues:96:5)

✔ Webpack Compiled successfully in 25.66s

[webpack-dev-middleware] wait until bundle finished: /static/js/bundle.js.map webpack 5.64.1 compiled successfully in 25662 ms

环境: win10 node 16.13

工程复现:可以使用以上配置,替换:https://github.com/X-neuron/antdFront.git 项目中的 webpack/webpack.config.js , npm run dev 即可

sorrycc commented 2 years ago

暂不支持 win,手上没有 win 机器,求 PR。

unknownzjc commented 2 years ago

@sorrycc 同样的问题在Mac OS 也出现了,我是用 Webpack5 + Vue 去搭建项目的。我有个 demo 可以复现,https://github.com/unknownzjc/example-webpack-vue-mfsu

unknownzjc commented 2 years ago

我把 @umijs/mfsu 的版本修改成 beta.9 就正常了。现在 npm 上发布的那个 beta.1 的版本不太对劲,不支持 esbuild