Angular 4首次加载缓慢求助:Windows服务器静态页面加载耗时过长
嘿,我来帮你搞定这个首次加载卡到爆的问题!既然你的主页是纯静态内容、没发起任何HTTP请求或数据库查询,那问题几乎肯定出在未优化的构建配置上——尤其是你没用到Angular CLI的情况下,默认的构建流程大概率没开启关键的优化选项,导致打包出来的文件体积超大,浏览器(特别是IE这种对现代JS不友好的家伙)加载和解析起来特别费劲。
下面是针对性的解决步骤,按优先级来:
1. 立刻启用AOT编译(最关键!)
Angular默认的JIT(即时编译)是在浏览器里把TypeScript编译成JavaScript,这个过程在首次加载时会占用大量时间,尤其是IE。而AOT(提前编译)是在构建阶段就把TS编译成优化后的JS,不仅文件体积小,浏览器直接就能解析,不用再在客户端编译。
如果你用webpack构建,可以这么配置:
- 安装
@ngtools/webpack和@angular/compiler-cli - 在webpack配置里替换掉原来的ts-loader,改用AngularCompilerPlugin:
const { AngularCompilerPlugin } = require('@ngtools/webpack'); module.exports = { // ...其他配置 module: { rules: [ { test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, loader: '@ngtools/webpack', }, ], }, plugins: [ new AngularCompilerPlugin({ tsConfigPath: './tsconfig.json', entryModule: './src/app/app.module#AppModule', sourceMap: false, // 生产环境关闭sourceMap减少体积 }), ], };
如果是用自定义脚本,直接调用ngc命令(Angular Compiler CLI)来替代tsc编译,它会自动处理AOT。
2. 压缩混淆代码 + Tree Shaking
代码压缩
用TerserPlugin(替代旧的UglifyJS,支持ES6+)压缩JS,去掉注释、空格,混淆变量名,大幅减小文件体积。webpack配置示例:
const TerserPlugin = require('terser-webpack-plugin'); module.exports = { optimization: { minimizer: [ new TerserPlugin({ parallel: true, // 多线程压缩加快构建速度 terserOptions: { compress: { drop_console: true, // 生产环境去掉console.log }, }, }), ], }, };
如果有CSS文件,用mini-css-extract-plugin配合cssnano压缩CSS:
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); module.exports = { module: { rules: [ { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'], }, ], }, plugins: [new MiniCssExtractPlugin()], optimization: { minimizer: [new CssMinimizerPlugin()], }, };
Tree Shaking
Tree Shaking能去掉代码中未被使用的部分(死代码),但需要满足两个条件:
- 在
tsconfig.json里设置module: "es2015"(或更高版本),确保输出ES模块(用import/export),而不是CommonJS的require - 构建工具(比如webpack)启用Tree Shaking,webpack 2+默认在生产环境开启,但要确保mode设置为
production
3. 代码拆分(Code Splitting)
把大的打包文件拆分成多个小文件,浏览器可以并行加载,而且第三方依赖(比如Angular核心库)可以单独打包,浏览器能缓存这些文件,下次访问更快。
拆分第三方依赖
用webpack的SplitChunksPlugin配置:
module.exports = { optimization: { splitChunks: { chunks: 'all', cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendors', chunks: 'all', }, }, }, }, };
这样会把node_modules里的依赖打包成单独的vendors.js文件。
路由懒加载
即使你的主页是静态的,如果整个应用的代码都打包在一起,首次加载还是会慢。给路由配置懒加载,只有访问对应路由时才加载那块代码:
// app-routing.module.ts const routes: Routes = [ { path: 'home', loadChildren: () => import('./home/home.module').then(m => m.HomeModule) }, // 其他路由同理 ];
4. IE浏览器专属优化
IE对ES6+语法支持极差,必须做转译和polyfill:
- 在
tsconfig.json里设置target: "es5",把TS编译成IE能识别的ES5代码 - 引入必要的polyfill,比如在
polyfills.ts里添加:
import 'core-js/es6'; import 'core-js/es7/reflect'; import 'zone.js/dist/zone'; import 'zone.js/dist/zone-polyfill'; // IE专属的zone polyfill
5. 服务器端开启Gzip压缩
这一步常常被忽略,但效果非常明显!Windows服务器(比如IIS)可以这么配置:
- 打开IIS管理器,找到你的站点
- 双击“压缩”功能
- 勾选“启用静态内容压缩”,如果有动态内容也可以勾选(不过你的主页是静态的,静态压缩就够了)
- 设置压缩文件类型包含
.js、.css、.html
Gzip能把文件体积压缩到原来的30%左右,大幅加快下载速度。
6. 分析打包体积找冗余
用webpack-bundle-analyzer插件分析打包后的文件,看看有没有意外引入的大模块:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { plugins: [new BundleAnalyzerPlugin()], };
运行构建后会打开一个可视化页面,直观看到每个模块的大小,针对性优化(比如替换体积大的第三方库,或者按需引入模块)。
按上面的步骤一步步来,尤其是AOT和压缩,应该能把首次加载时间降到几秒以内,IE的情况也会大幅改善!
内容的提问来源于stack exchange,提问作者Dorni

