Apakah yang perlu saya lakukan jika projek itu terlalu besar? Bagaimana untuk membahagikan projek Angular dengan munasabah?

青灯夜游
Lepaskan: 2022-09-15 19:47:17
ke hadapan
3188 orang telah melayarinya

SudutProjek ini terlalu besar, bagaimana untuk membahagikannya secara munasabah? Artikel berikut akan memperkenalkan kepada anda cara membahagikan projek Angular secara munasabah. Saya harap ia akan membantu anda!

Apakah yang perlu saya lakukan jika projek itu terlalu besar? Bagaimana untuk membahagikan projek Angular dengan munasabah?

Salah satu kritikan tentang Angular ialah ia sangat besar selepas pembungkusan Jika anda tidak berhati-hati main.js ia menjadi besar yang tidak masuk akal , sama ada saiz besar , data besar atau trafik besar, hanya ada satu idea: pemisahan. Ditambah dengan mekanisme caching pelayar, kelajuan capaian projek boleh dioptimumkan. [Tutorial berkaitan yang disyorkan: "tutorial sudut"]

Kod yang berkaitan untuk artikel ini ialah di: https://github.com/Vibing/angular-webpack

Pisah idea

  • Keseluruhan projek termasuk: pustaka pergantungan yang kukuh (rangka kerja sudut itu sendiri), pustaka komponen UI dan pustaka pihak ketiga, dan bahagian kod perniagaan;

  • Dimensi tingkah laku pengguna: semua lawatan pengguna adalah berdasarkan laluan, satu laluan setiap halaman; dua perkara di atas, berdasarkan yang pertama Anda boleh membungkus perpustakaan dan perpustakaan yang sangat bergantung kepada yang jarang berubah menjadi

    , yang boleh termasuk
  • ,
,

, vendor_library dan pakej lain yang serupa, UI perpustakaan komponen atau @angular/common Tidak disyorkan untuk membungkus jenis perpustakaan ini bersama-sama, kerana kita perlu menggunakan TreeShaking, dan tidak perlu membungkus kod yang tidak digunakan, jika tidak, ia hanya akan meningkatkan saiz. @angular/core@angular/forms Memandangkan pakej pergantungan yang kukuh telah sedia, mari pakejkan kod perniagaan berdasarkan perkara 2. Kami menggunakan @angular/router berasaskan penghalaan untuk pembungkusan. Ideanya sangat mudah. ​​Mana-mana halaman yang dilawati pengguna, js yang sepadan dengan halaman itu dimuat turun Tidak perlu membungkus halaman yang tidak dilawati ini bukan sahaja akan meningkatkan saiz, tetapi juga meningkatkan masa muat turun, dan pengguna pengalaman juga akan merosot. lodash

Konfigurasi webpack tersuaicode spliting

Jika kita ingin menggunakan DLL untuk mengimport pakej yang sangat bergantung kepada vendor, kita mesti menggunakan fungsi webpack, yang telah dibenamkan dalam Angular CLI webpack, tetapi konfigurasi ini adalah kotak hitam kepada kami. Angular membolehkan kami menyesuaikan konfigurasi webpack adalah seperti berikut:

Pasang

dan
  • @angular-builders/custom-webpack@angular-devkit/build-angularBuat yang baharu webpack.extra.config.ts digunakan untuk konfigurasi webpack

  • Buat pengubahsuaian berikut dalam angular.json

  • Gunakan DLL
...
"architect": {
  "build": {
    "builder": "@angular-builders/custom-webpack:browser",
    "options": {
      ...
      "customWebpackConfig": {
        // 引用要拓展的 webpack 配置
        "path": "./webpack.extra.config.ts",
        // 是否替换重复插件
        "replaceDuplicatePlugins": true
      }
    }
  },
  "serve": {
    "builder": "@angular-builders/custom-webpack:dev-server",
    "options": {
      "browserTarget": "angular-webpack:build"
    }
  }
  ...
Salin selepas log masuk

Selepas anda boleh menyesuaikan konfigurasi webpack, buat fail webpack.dll.js baharu untuk menulis konfigurasi DLL:

Kemudian teruskan dalam pengenalan webpack.extra.config.ts dll

const path = require("path");
const webpack = require("webpack");

module.exports = {
  mode: "production",
  entry: {
    vendor: [
      "@angular/platform-browser",
      "@angular/platform-browser-dynamic",
      "@angular/common",
      "@angular/core",
      "@angular/forms",
      "@angular/router"
    ],
  },
  output: {
    path: path.resolve(__dirname, "./dll"),
    filename: "[name].dll.js",
    library: "[name]_library",
  },

  plugins: [
    new webpack.DllPlugin({
      context: path.resolve(__dirname, "."),
      path: path.join(__dirname, "./dll", "[name]-manifest.json"),
      name: "[name]_library",
    }),
  ],
};
Salin selepas log masuk
Akhir sekali, tambahkan arahan untuk membungkus dll dalam package.json:

Selepas melaksanakan

, akan ada folder dll pada akar projek, yang mengandungi kandungan berpakej:
import * as path from 'path';
import * as webpack from 'webpack';

export default {
  plugins: [
    new webpack.DllReferencePlugin({
      manifest: require('./dll/vendor-manifest.json'),
      context: path.resolve(__dirname, '.'),
    })
  ],
} as webpack.Configuration;
Salin selepas log masuk

"dll": "rm -rf dll && webpack --config webpack.dll.js"npm run dll

Selepas pembungkusan selesai, kita perlu menggunakan

dalam projek dan mengkonfigurasinya dalam :

vendor.dll.jsAnda boleh melihatnya selepas pembungkusan Bagi angular.json, ia telah diperkenalkan:

"architect": {
  ...
  "build": {
    ...
    "options": {
      ...
       "scripts": [
         {
            "input": "./dll/vendor.dll.js",
            "inject": true,
            "bundleName": "vendor_library"
         }
       ]
    }
  }
}
Salin selepas log masuk

vendor_library.js

DLL digunakan untuk membungkus dan menggabungkan pakej yang sangat bergantung yang tidak kerap dikemas kini ke dalam fail js, yang biasanya digunakan untuk membungkus Sesuatu Angular tentang rangka kerja itu sendiri. Apabila pengguna melawat buat kali pertama, penyemak imbas akan memuat turun

dan menyimpannya di cache Setiap lawatan berikutnya akan diambil terus daripada cache Penyemak imbas hanya akan memuat turun js kod perniagaan dan tidak akan memuat turun rangka kerja kod, yang meningkatkan prestasi kelajuan pemuatan aplikasi meningkatkan pengalaman pengguna.

ps: Cincang di belakang vendor_library hanya akan ditukar jika kod di dalamnya ditukar semasa pembungkusan, jika tidak, ia tidak akan berubah.

vendor_library.js

Pemisahan Kod peringkat laluan

DLL telah menguruskan kod dalam bahagian rangka kerja Mari lihat cara melaksanakan pemuatan atas permintaan halaman peringkat penghalaan dalam Angular. Seketika, bagaimanakah anda melakukan pemisahan kod peringkat laluan dalam React atau Vue? Ia mungkin seperti ini:

Rumah di sini menunjuk kepada komponen yang sepadan, tetapi kaedah ini tidak boleh digunakan dalam Angular Kod hanya boleh dibahagikan dalam unit modul:

{
  path:'/home',
  component: () => import('./home')
}
Salin selepas log masuk
Kemudian gunakan penghalaan dalam modul tertentu untuk mengakses komponen tertentu:

{
  path:'/home',
  loadChild: ()=> import('./home.module').then(m => m.HomeModule)
}
Salin selepas log masuk
Walaupun anda tidak boleh terus

komponen dalam penghala, Angular menyediakan

import dinamik komponen
import { HomeComponent } from './home.component'

{
  path:'',
  component: HomeComponent
}
Salin selepas log masuk
Fungsi:

import() Dengan cara ini, apabila mengakses halaman tertentu melalui penghalaan, selagi kandungan halaman yang diakses digunakan import() dan diimport secara dinamik dengan komponen

, kesan halaman LazyLoad sudah boleh dicapai?
@Component({
  selector: 'app-home',
  template: ``,
})
export class HomeContainerComponent implements OnInit {
  constructor(
      private vcref: ViewContainerRef,
      private cfr: ComponentFactoryResolver
  ){}
  
  ngOnInit(){
    this.loadGreetComponent()
  }

  async loadGreetComponent(){
      this.vcref.clear();
      // 使用 import() 懒加载组件
      const { HomeComponent } = await import('./home.component');
      let createdComponent = this.vcref.createComponent(
        this.cfr.resolveComponentFactory(HomeComponent)
      );  
  }
}
Salin selepas log masuk

答案是可以的。但是这样会有一个大问题:被 lazyLoad 的组件中,其内容仅仅是当前组件的代码,并不包含引用的其他模块中组件的代码。

原因是 Angular 应用由多个模块组成,每个模块中需要的功能可能来自其他模块,比如 A 模块里要用到 table 组件,而 table 需取自于 ng-zorro-antd/table 模块。打包时 Angular 不像 React 或 Vue 可以把当前组件和用到的其他包一起打包,以 React 为例:在 A 组件引入 table 组件,打包时 table 代码会打包到 A 组件中。而 Angular 中,在 A 组件中使用 table 组件时,并且使用 imprt() 对 A 组件进行动态加载,打包出来的 A 组件并不包含 table 的代码, 而是会把 table 代码打包到当前模块中去,如果一个模块中包含多个页面,这么多页面用了不少UI组件,那么打包出来的模块肯定会很大。

那么就没有别的方法了吗?答案是有的,那就是把每个页面拆成一个 module,每个页面所用到的其他模块或组件由当前页面对应的模块所承担。

上图中 dashboard 作为一个模块,其下有两个页面,分别是 monitorwelcome

dashboard.module.ts:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  {
    path: 'welcome',
    loadChildren: () => import('./welcome/welcome.module').then((m) => m.WelcomeModule),
  },
  {
    path: 'monitor',
    loadChildren: () => import('./monitor/monitor.module').then((m) => m.MonitorModule),
  },
];

@NgModule({
  imports: [CommonModule, RouterModule.forChild(routes)],
  exports: [RouterModule],
  declarations: [],
})
export class DashboardModule {}
Salin selepas log masuk

在模块中使用路由 loadChildren 来 lazyLoad 两个页面模块,现在再看看 WelcomeModule:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { WelcomeComponent } from './welcome.component';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  { path: '', component: WelcomeComponent }
];
@NgModule({
  declarations: [WelcomeComponent],
  imports: [RouterModule.forChild(routes), CommonModule]
})
export class WelcomeModule {}
Salin selepas log masuk

就是这么简单,就把页面级的 lazyLoad 完成了。当需要使用外部组件时,比如 table 组件,只要在 imports 引入即可:

import { NzTableModule } from 'ng-zorro-antd/table';

@NgModule({
  ...
  imports: [..., NzTableModule]
})
export class WelcomeModule {}
Salin selepas log masuk

题外话:我更喜欢 React 的拆分方式,举个例子:React 中使用 table 组件,table 组件本身代码量比较大,如果很多页面都使用 table,那么每个页面都会有 table 代码,造成不必要的浪费。所以可以配合 import()table组件单拉出来,打包时 table 作为单独的 js 被浏览器下载并提供给需要的页面使用,所有页面共享这一份 js即可。但 Angular 做不到,它无法在模块的 imports 中使用 import()的模块 。

后续

以上都是对项目代码做了比较合理的拆分,后续会对 Angular 性能上做合理的优化,主要从编译模式、变更检测、ngFor、Worker等角度来阐述。

更多编程相关知识,请访问:编程视频!!

Atas ialah kandungan terperinci Apakah yang perlu saya lakukan jika projek itu terlalu besar? Bagaimana untuk membahagikan projek Angular dengan munasabah?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:segmentfault.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!