webpack太多动态引入的时候dev-server速度特别慢
问题描述
项目里大概有一百多个路由
本意是通过react.lazy实现代码切割
但是开发的时候挠破了头
webpack-dev-server编译的时候速度极慢 改个文本都需要大概10s左右
而且诡异的是以下这种情况:
初次启动server 浏览器加载的js数量
修改部分代码热重载后
感觉是一次性加载了所有的切割代码?
问题出现的环境背景及自己尝试过哪些方法
参考issue:https://github.com/facebook/c...
相关代码
// 请把代码文本粘贴到下方(请勿用图片代替代码)
代码基本如下 就是switch里的路由数量大概是一百多个
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Suspense>
</Router>
);
webpack.config.js
'use strict'
const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const resolve = require('resolve')
const PnpWebpackPlugin = require('pnp-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin')
const TerserPlugin = require('terser-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const safePostCssParser = require('postcss-safe-parser')
const ManifestPlugin = require('webpack-manifest-plugin')
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin')
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin')
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin')
const paths = require('./paths')
const getClientEnvironment = require('./env')
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin')
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin')
const typescriptFormatter = require('react-dev-utils/typescriptFormatter')
const os = require('os');
const threadPoolCount = os.cpus().length;
const HappyPack = require('happypack');
const threadPool = HappyPack.ThreadPool({size: threadPoolCount});
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false'
const useTypeScript = fs.existsSync(paths.appTsConfig)
const cssRegex = /\.css$/
const cssModuleRegex = /\.module\.css$/
const happyPackConfig = {
threadPool,
verbose: false
}
module.exports = function(webpackEnv) {
const isEnvDevelopment = webpackEnv === 'development'
const isEnvProduction = webpackEnv === 'production'
const publicPath = isEnvProduction ? paths.servedPath : isEnvDevelopment && '/'
const shouldUseRelativeAssetPaths = publicPath === './'
const publicUrl = isEnvProduction ? publicPath.slice(0, -1) : isEnvDevelopment && ''
const env = getClientEnvironment(publicUrl)
const getStyleLoaders = (cssOptions, preProcessor, preProcessorOptions = {}) => {
const loaders = [
isEnvDevelopment && require.resolve('style-loader'),
isEnvProduction && {
loader: MiniCssExtractPlugin.loader,
options: Object.assign({}, shouldUseRelativeAssetPaths ? {publicPath: '../../'} : undefined)
},
{
loader: require.resolve('css-loader'),
options: cssOptions
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
})
],
sourceMap: isEnvProduction && shouldUseSourceMap
}
}
].filter(Boolean)
if (preProcessor) {
loaders.push({
loader: require.resolve(preProcessor),
options: {
sourceMap: isEnvProduction && shouldUseSourceMap,
...preProcessorOptions
}
})
}
return loaders
}
return {
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
bail: isEnvProduction,
devtool: isEnvProduction
? shouldUseSourceMap
? 'source-map'
: false
: isEnvDevelopment && 'cheap-module-source-map',
entry: [
isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient'),
'babel-polyfill',
paths.appIndexJs
].filter(Boolean),
output: {
path: isEnvProduction ? paths.appBuild : undefined,
pathinfo: isEnvDevelopment,
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
publicPath,
devtoolModuleFilenameTemplate: isEnvProduction
? info => path.relative(paths.appSrc, info.absoluteResourcePath).replace(/\\/g, '/')
: isEnvDevelopment && (info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'))
},
optimization: {
minimize: isEnvProduction,
minimizer: [
new TerserPlugin({
terserOptions: {
parse: {
ecma: 8
},
compress: {
ecma: 5,
warnings: false,
comparisons: false,
inline: 2
},
mangle: {
safari10: true
},
output: {
ecma: 5,
comments: false,
ascii_only: true
}
},
parallel: true,
cache: true,
sourceMap: shouldUseSourceMap
}),
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
parser: safePostCssParser,
map: shouldUseSourceMap
? {
inline: false,
annotation: true
}
: false
}
})
],
splitChunks: isEnvProduction ? {
chunks: 'all',
name: false
} : false,
runtimeChunk: true
},
resolve: {
modules: ['node_modules'].concat(
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
extensions: paths.moduleFileExtensions
.map(ext => `.${ext}`)
.filter(ext => useTypeScript || !ext.includes('ts')),
alias: {
'react-native': 'react-native-web'
},
plugins: [
PnpWebpackPlugin,
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson])
]
},
resolveLoader: {
plugins: [
PnpWebpackPlugin.moduleLoader(module)
]
},
module: {
strictExportPresence: true,
rules: [
{parser: {requireEnsure: false}},
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
use: 'happypack/loader?id=js'
},
{
test: /\.(js|mjs)$/,
exclude: /@babel(?:\/|\\{1,2})runtime/,
use: 'happypack/loader?id=outsideJs'
},
{
test: cssRegex,
exclude: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap
}),
sideEffects: true
},
{
use: 'happypack/loader?id=file',
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/]
}
]
}
]
},
plugins: [
new HappyPack({
...happyPackConfig,
id: 'js',
loaders: [
{
loader: 'babel-loader',
options: {
customize: require.resolve('babel-preset-react-app/webpack-overrides'),
plugins: [
[
require.resolve('babel-plugin-named-asset-import'),
{
loaderMap: {
svg: {
ReactComponent: '@svgr/webpack?-svgo,+ref![path]'
}
}
}
],
['import', {libraryName: 'antd-mobile', style: true}]
],
cacheDirectory: true,
cacheCompression: isEnvProduction,
compact: isEnvProduction
}
}
]
}),
new HappyPack({
...happyPackConfig,
id: 'outsideJs',
loaders: [
{
loader: require.resolve('babel-loader'),
options: {
babelrc: false,
configFile: false,
compact: false,
presets: [[require.resolve('babel-preset-react-app/dependencies'), {helpers: true}]],
cacheDirectory: true,
cacheCompression: isEnvProduction,
sourceMaps: false
}
}
]
}),
new HappyPack({
...happyPackConfig,
id: 'fontModule',
loaders: ['file-loader']
}),
new HappyPack({
...happyPackConfig,
id: 'file',
loaders: [
{
loader: 'file-loader',
options: {
name: 'static/media/[name].[hash:8].[ext]'
}
}
]
}),
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
)
),
isEnvProduction &&
shouldInlineRuntimeChunk &&
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime~.+[.]js/]),
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
new ModuleNotFoundPlugin(paths.appPath),
new webpack.DefinePlugin(env.stringified),
isEnvDevelopment && new webpack.HotModuleReplacementPlugin(),
isEnvDevelopment && new CaseSensitivePathsPlugin(),
isEnvDevelopment && new WatchMissingNodeModulesPlugin(paths.appNodeModules),
isEnvProduction &&
new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:8].css',
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css'
}),
new ManifestPlugin({
fileName: 'asset-manifest.json',
publicPath
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
isEnvProduction &&
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim: true,
exclude: [/\.map$/, /asset-manifest\.json$/],
importWorkboxFrom: 'cdn',
navigateFallback: publicUrl + '/index.html',
navigateFallbackBlacklist: [
new RegExp('^/_'),
new RegExp('/[^/]+\\.[^/]+$')
]
}),
useTypeScript &&
new ForkTsCheckerWebpackPlugin({
typescript: resolve.sync('typescript', {
basedir: paths.appNodeModules
}),
async: isEnvDevelopment,
useTypescriptIncrementalApi: true,
checkSyntacticErrors: true,
tsconfig: paths.appTsConfig,
reportFiles: [
'**',
'!**/*.json',
'!**/__tests__/**',
'!**/?(*.)(spec|test).*',
'!**/src/setupProxy.*',
'!**/src/setupTests.*'
],
watch: paths.appSrc,
silent: true,
formatter: isEnvProduction ? typescriptFormatter : undefined
}),
].filter(Boolean),
node: {
module: 'empty',
dgram: 'empty',
dns: 'mock',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
},
performance: false
}
}
webpackDevServer.js
'use strict';
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
const ignoredFiles = require('react-dev-utils/ignoredFiles');
const paths = require('./paths');
const fs = require('fs');
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const host = process.env.HOST || '0.0.0.0';
module.exports = function(proxy, allowedHost) {
return {
disableHostCheck:
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true',
compress: true,
clientLogLevel: 'none',
contentBase: paths.appPublic,
watchContentBase: true,
hot: true,
publicPath: '/',
quiet: true,
watchOptions: {
ignored: ignoredFiles(paths.appSrc),
},
https: protocol === 'https',
host,
overlay: false,
historyApiFallback: {
disableDotRule: true,
},
public: allowedHost,
proxy,
before(app, server) {
if (fs.existsSync(paths.proxySetup)) {
require(paths.proxySetup)(app);
}
app.use(evalSourceMapMiddleware(server));
app.use(errorOverlayMiddleware());
app.use(noopServiceWorkerMiddleware());
},
};
};
你期待的结果是什么?实际看到的错误信息又是什么?
使用lazy切割代码如何加快开发时候的编译速度
或者说lazy的正确使用姿势
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
想问下有没基于creat-react-app做过配置
runtimeChunk: true 这个影响到了吧
这里的逻辑是开发都打包到static/js/bundle.js,当时你runtimeChunk为true时chunkFilename把filename给覆盖了吧
已解决
借助babel插件 https://github.com/airbnb/bab...
具体做法 参考https://panjiachen.github.io/...