Javascript Angular2 加载时文件请求过多
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35280582/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Angular2 too many file requests on load
提问by Marcos Basualdo
I'm making a website using Angular2
and I'm having what i suppose is an issue. On the first load of my angular page, SystemJS
is making more than 500 hundred requests to retrieve every Angular2
file in angular2/src
directory. In total, the first load downloads more than 4MB and it takes more than 14 seconds to start.
我正在使用一个网站Angular2
,但我遇到了我认为的问题。在我的 angular 页面的第一次加载时,SystemJS
发出超过 50000 个请求来检索目录中的每个Angular2
文件angular2/src
。总的来说,第一次加载下载超过 4MB,启动时间超过 14 秒。
My index.html
does the following scripts includes:
我index.html
的以下脚本包括:
<script src="libs/angular2/bundles/angular2-polyfills.js"></script>
<script src="libs/systemjs/dist/system.src.js"></script>
<script src="libs/rxjs/bundles/Rx.js"></script>
<script src="libs/angular2/bundles/angular2.min.js"></script>
<script src="libs/angular2/bundles/http.dev.js"></script>
<script src="libs/jquery/jquery.js"></script>
<script src="libs/lodash/lodash.js"></script>
<script src="libs/bootstrap/js/bootstrap.js"></script>
And my systemJs initialization code looks like this:
我的 systemJs 初始化代码如下所示:
<script>
System.config({
defaultJSExtensions: true,
paths: {
'*': 'libs/*',
'app/*': 'app/*'
},
packageConfigPaths: ['libs/*/package.json'],
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('app/main')
.then(null, console.error.bind(console));
</script>
My public folder has the following structure:
我的公用文件夹具有以下结构:
.
├── img
├── styles
├── app
├── libs
| └── angular2
| └── systemjs
| └── rxjs
| └── jquery
| └── lodash
| └── bootstrap
└── index.html
A couple of screenshots of some of the js files that are being requested:
Is there a way to avoid all of those requests?
有没有办法避免所有这些请求?
采纳答案by David Herod
I had the exact same problem, was actually looking at this post for an answer. Here is what I did to solve the problem.
我遇到了完全相同的问题,实际上是在看这篇文章以寻求答案。这是我为解决问题所做的工作。
- Modify your project to use webpack. Follow this short tutorial: Angular2 QuickStart SystemJS To Webpack
- This method will give you a single javascript file however it is quite large (my project file was over 5MB) and needs to be minified. To do this I installed webpack globaly:
npm install webpack -g
. Once installed, runwebpack -p
from your apps root directory. This brought my file size down to about 700KB
- 修改您的项目以使用 webpack。按照这个简短的教程: Angular2 QuickStart SystemJS 到 Webpack
- 此方法将为您提供一个 javascript 文件,但它非常大(我的项目文件超过 5MB)并且需要缩小。为此,我全局安装了 webpack:
npm install webpack -g
. 安装后,webpack -p
从您的应用程序根目录运行。这使我的文件大小减少到大约 700KB
From 20 seconds and 350 requests down to 3 seconds and 7 requests.
从 20 秒和 350 个请求减少到 3 秒和 7 个请求。
回答by MrCroft
I see you already have a response, which is good of course. BUT for those who want to use systemjs(like I also do), and not go to webpack, you can still bundle the files. However, it does involve using another tool also (I use gulp). So... you would have the folowing systemjs config (not in the html, but in a separate file - let's call it "system.config.js"):
我看到你已经有了回应,这当然很好。但是对于那些想要使用systemjs(就像我也这样做)而不是去 webpack 的人,你仍然可以捆绑这些文件。但是,它也涉及使用另一个工具(我使用 gulp)。所以......你会有以下 systemjs 配置(不是在 html 中,而是在一个单独的文件中 - 我们称之为“system.config.js”):
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': 'dist/app', // this is where your transpiled files live
'rxjs': 'node_modules/rxjs',
'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api', // this is something new since angular2 rc.0, don't know what it does
'@angular': 'node_modules/@angular'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'boot.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { defaultExtension: 'js' }
};
var packageNames = [
'@angular/common',
'@angular/compiler',
'@angular/core',
'@angular/http',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
//'@angular/router', // I still use "router-deprecated", haven't yet modified my code to use the new router that came with rc.0
'@angular/router-deprecated',
'@angular/http',
'@angular/testing',
'@angular/upgrade'
];
// add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' }
packageNames.forEach(function(pkgName) {
packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
var config = {
map: map,
packages: packages
};
// filterSystemConfig - index.html's chance to modify config before we register it.
if (global.filterSystemConfig) { global.filterSystemConfig(config); }
System.config(config);
})(this);
Then, in your gulpfile.js you would build a bundle like this (using the info from system.config.js
and tsconfig.json
files):
然后,在您的 gulpfile.js 中,您将构建一个这样的包(使用来自system.config.js
和tsconfig.json
文件的信息):
var gulp = require('gulp'),
path = require('path'),
Builder = require('systemjs-builder'),
ts = require('gulp-typescript'),
sourcemaps = require('gulp-sourcemaps');
var tsProject = ts.createProject('tsconfig.json');
var appDev = 'dev/app'; // where your ts files are, whatever the folder structure in this folder, it will be recreated in the below 'dist/app' folder
var appProd = 'dist/app';
/** first transpile your ts files */
gulp.task('ts', () => {
return gulp.src(appDev + '/**/*.ts')
.pipe(sourcemaps.init({
loadMaps: true
}))
.pipe(ts(tsProject))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(appProd));
});
/** then bundle */
gulp.task('bundle', function() {
// optional constructor options
// sets the baseURL and loads the configuration file
var builder = new Builder('', 'dist/system.config.js');
/*
the parameters of the below buildStatic() method are:
- your transcompiled application boot file (the one wich would contain the bootstrap(MyApp, [PROVIDERS]) function - in my case 'dist/app/boot.js'
- the output (file into which it would output the bundled code)
- options {}
*/
return builder
.buildStatic(appProd + '/boot.js', appProd + '/bundle.js', { minify: true, sourceMaps: true})
.then(function() {
console.log('Build complete');
})
.catch(function(err) {
console.log('Build error');
console.log(err);
});
});
/** this runs the above in order. uses gulp4 */
gulp.task('build', gulp.series(['ts', 'bundle']));
So, when running "gulp build", you will get the "bundle.js" file with everything you need. Sure, you also need a few more packages for this gulp bundle task to work:
因此,当运行“gulp build”时,您将获得包含您需要的所有内容的“bundle.js”文件。当然,你还需要一些更多的包来让这个 gulp bundle 任务工作:
npm install --save-dev github:gulpjs/gulp#4.0 gulp-typescript gulp-sourcemaps path systemjs-builder
Also, make sure that in your tsconfig.json you have "module":"commonjs"
.
Here is my tsconfig.json which is used in my 'ts'
gulp task:
另外,请确保在您的 tsconfig.json 中有"module":"commonjs"
. 这是我在 gulp'ts'
任务中使用的 tsconfig.json :
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"exclude": [
"node_modules",
"typings/main",
"typings/main.d.ts"
]
}
Then, in your html file you only need to include this:
然后,在您的 html 文件中,您只需要包含以下内容:
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="dist/app/bundle.js"></script>
And that's it... I got from 600 requests, 4mb in about 5 seconds... to 20 requests, 1.4mb in 1.6 seconds (local development machine). But these 20 requests ~1.4mb in 1.6 seconds also include some other js and css that the admin theme came with plus a few html templates that get required on the first load, I prefer to use external templates - templateUrl: '', instead of inline ones, written in my component.ts file. Sure, for an app that would have millions of users, this still wouldn't be enough. Also server-side rendering for initial load and cache system should be implemented, I actually managed to do that with angular universal, but on Angular2 beta (took about 200-240 millisecondsto load the initial render of the same admin app that above takes 1.6 seconds - I know: WOW!). Now it's incompatible since Angular2 RC came out, but I'm sure the guys doing universal will get it up to speed soon, specially since ng-conf is coming up. Plus, they're also planing to make Angular Universal for PHP, ASP and a few other - right now it's only for Nodejs.
就是这样......我从 600 个请求,大约 5 秒内获得 4mb......到 20 个请求,1.6 秒内获得 1.4mb(本地开发机器)。但是这 20 个请求在 1.6 秒内约 1.4mb 还包括管理主题附带的一些其他 js 和 css 以及一些在第一次加载时需要的 html 模板,我更喜欢使用外部模板 - templateUrl: '',而不是内联的,写在我的 component.ts 文件中。当然,对于拥有数百万用户的应用程序来说,这仍然不够。还应该实现初始加载和缓存系统的服务器端渲染,我实际上设法用 angular 通用来做到这一点,但是在 Angular2 beta 上(大约需要200-240 毫秒来加载上面需要 1.6 的相同管理应用程序的初始渲染秒 - 我知道:哇!)。现在它不兼容,因为 Angular2 RC 出来了,但我相信做通用的人很快就会加快速度,特别是因为 ng-conf 即将推出。另外,他们还计划为 PHP、ASP 和其他一些工具制作 Angular Universal——现在它只适用于 Nodejs。
Edit:Actually, I've just found out that on NG-CONF they said Angular Universal already supports ASP (but it doesn't support Angular2 > beta.15 :)) ... but let's give them some time, RC just came out a few days ago
编辑:实际上,我刚刚发现在 NG-CONF 上,他们说 Angular Universal 已经支持 ASP(但它不支持 Angular2 > beta.15 :))...但是让我们给他们一些时间,RC 刚刚来几天前出来
回答by FreeBird72
I found a simple solution, using browserify & uglifyjs on mgechev's angular2-seed repository
我找到了一个简单的解决方案,在mgechev 的 angular2-seed 存储库上使用browserify和 uglifyjs
Here's my version:
这是我的版本:
pacakge.json:
pacakge.json:
{
...
"scripts": {
"build_prod": "npm run clean && npm run browserify",
"clean": "del /S/Q public\dist",
"browserify": "browserify -s main public/YourMainModule.js > public/dist/bundle.js && npm run minify",
"minify": "uglifyjs public/dist/bundle.js --screw-ie8 --compress --mangle --output public/dist/bundle.min.js"
},
...
"devDependencies": {
"browserify": "^13.0.1",
"typescript": "^1.9.0-dev.20160625-1.0",
"typings": "1.0.4",
"uglifyjs": "^2.4.10"
}
}
- Build your project.
- Run: npm run build_prodIt'll create bundle.js & bundle.min.js under public\dist directory.
- Edit your
index.html
file: Instead of runningSystem.import('YourMainModule')... ,
add<script src="/dist/bundle.min.js"></script>
- 构建您的项目。
- 运行:npm run build_prod会在public\dist目录下创建bundle.js & bundle.min.js。
- 编辑您的
index.html
文件:而不是运行System.import('YourMainModule')... ,
添加<script src="/dist/bundle.min.js"></script>
回答by Thierry Templier
I think that your question is related to this one:
我认为你的问题与这个有关:
To have something ready for production (and speed it up), you need to package it.
要为生产做好准备(并加快生产速度),您需要对其进行打包。
I mean transpiling all files into JavaScript ones and concat them the same way Angular2 does for example. This way you will have several modules contained into a single JS file. This way you will reduce the number of HTTP calls to load your application code into the browser.
我的意思是将所有文件转换为 JavaScript 文件并以与 Angular2 相同的方式连接它们,例如。这样,您将在一个 JS 文件中包含多个模块。这样,您将减少将应用程序代码加载到浏览器的 HTTP 调用次数。
回答by lthh89vt
@FreeBird72 Your answer is awesome.
@FreeBird72 你的回答很棒。
If you want to use SystemJS for development and speed up the production server like I do. Check this out.
如果你想像我一样使用 SystemJS 进行开发并加速生产服务器。看一下这个。
NOTE:Only import the components that you use, DO NOT import from the whole package.
注意:仅导入您使用的组件,不要从整个包中导入。
Eg: If you want to use Modal from ng2-bootstrap.
例如:如果你想使用 ng2-bootstrap 中的 Modal。
import {MODAL_DIRECTIVES} from "ng2-bootstrap/components/modal";
Instead of:
代替:
import {MODAL_DIRECTIVES} from "ng2-bootstrap/ng2-bootstrap";
This will import the modal component instead of the whole ng2-bootstrap
这将导入模态组件而不是整个 ng2-bootstrap
Then follow the answer from @FreeBird72
然后按照@FreeBird72的答案进行操作
Add this package.json
添加这个 package.json
{
...
"scripts": {
...
"prod": "npm run tsc && npm run browserify",
"browserify": "browserify -s main dist/main.js > dist/bundle.js && npm run minify",
"minify": "uglifyjs dist/bundle.js --screw-ie8 --compress --mangle --output dist/bundle.min.js",
...
},
"devDependencies": {
...
"browserify": "^13.0.1",
"uglifyjs": "^2.4.10",
...
}
...
}
Then you can npm run tsc
on development and npm run prod
on production server
Also remove System.import(....
from your index.html and change it to <script src="/dist/bundle.min.js"></script>
然后你可以npm run tsc
在开发和npm run prod
生产服务器上也System.import(....
从你的 index.html 中删除并将其更改为<script src="/dist/bundle.min.js"></script>
回答by basarat
On the first load of my angular page, systemjs is making more than 500 hundred requests to retrieve every angular2 file in angular2/src directory. In total, the first load downloads more than 4mb and it takes more than 14s to start.
在我的 angular 页面的第一次加载时,systemjs 发出超过 50000 个请求来检索 angular2/src 目录中的每个 angular2 文件。总的来说,第一次加载下载超过 4mb,启动时间超过 14 秒。
The SystemJs workflows are fairly new and don't have enough research in them for best deployment.
SystemJs 工作流是相当新的,没有足够的研究来实现最佳部署。
Suggest going back to commonjs
+ webpack
. More : https://basarat.gitbooks.io/typescript/content/docs/quick/browser.html
建议回到commonjs
+ webpack
。更多:https: //basarat.gitbooks.io/typescript/content/docs/quick/browser.html
Here is an example : https://github.com/AngularClass/angular2-webpack-starter
这是一个例子:https: //github.com/AngularClass/angular2-webpack-starter
回答by Harry
The Angular command line interface now supports bundling (with tree-shaking to strip out unused code from imports), minification, and ahead-of-time template compilation, which not only hugely minimises the number of requests made, but also makes the bundle very small. It uses WebPack underneath.
Angular 命令行界面现在支持捆绑(通过摇树从导入中去除未使用的代码)、缩小和提前模板编译,这不仅极大地减少了发出的请求数量,而且使捆绑非常小的。它在下面使用 WebPack。
It's incredibly easy to make production builds with it:
使用它进行生产构建非常容易:
ng build --prod --aot
回答by Harry
If you want to stick with SystemJS, you can bundle your app with JSPM. I've had good success with this so far, using JSPM's bundle-sfx
command to make single JS files for Angular 2 apps.
如果您想坚持使用 SystemJS,您可以将您的应用程序与JSPM捆绑在一起。到目前为止,我在这方面取得了很好的成功,使用 JSPM 的bundle-sfx
命令为 Angular 2 应用程序制作单个 JS 文件。
There's some useful information in this Gist, and there's a seed project.
回答by Wong Kim Wah
I am using AG2 RC version While using MrCroft's solution with systemjs-builder, i was hitting a lot of issues like: error TS2304: Cannot find name 'Map' error TS2304: Cannot find name 'Promise'...
我正在使用 AG2 RC 版本在将 MrCroft 的解决方案与 systemjs-builder 一起使用时,我遇到了很多问题,例如:错误 TS2304:找不到名称“地图”错误 TS2304:找不到名称“承诺”...
After many tries, i added:
///<reference path="../../typings/index.d.ts" />
into my boot.ts and now I got my bundle file compiled.
经过多次尝试,我添加:
///<reference path="../../typings/index.d.ts" />
到我的 boot.ts 中,现在我编译了我的包文件。