1# Dynamic Import 2 3Dynamic imports support conditional loading and partial reflection, enhancing page load speed. It allows loading HSP modules, HAR modules, ohpm packages, and native libraries. It also enables module decoupling when only variables are dynamically imported between HAR modules. 4 5## When to Use 6Dynamic imports can be used in application development when you need to import modules conditionally or on-demand, as an alternative to [static import](../quick-start/introduction-to-arkts.md#static-import). The following are some cases where you might want to use dynamic import: 7 8* Statically imported modules significantly slow the loading of your code and are rarely used or not immediately needed. 9* Statically imported modules consume a large amount of system memory and are rarely used. 10* The imported module does not exist at load time and needs to be fetched asynchronously. 11* The import specifier string needs to be constructed dynamically. Static imports only support static specifiers. 12* The imported module has side effects (which can be understood as code that runs directly in the module) that are only needed when certain conditions are triggered. 13 14## Service Expansion Scenarios 15As aforementioned, in addition to conditional loading, dynamic imports can implement partial reflection. In the following example, an HAP dynamically imports a HAR package (**harlibrary**) and calls its static member function **staticAdd()**, instance member function **instanceAdd()**, and global function **addHarlibrary()**. 16```typescript 17// harlibrary's src/main/ets/utils/Calc.ets 18export class Calc { 19 public static staticAdd(a:number, b:number):number { 20 let c = a + b; 21 console.info('DynamicImport I am harlibrary in staticAdd, %d + %d = %d', a, b, c); 22 return c; 23 } 24 25 public instanceAdd(a:number, b:number):number { 26 let c = a + b; 27 console.info('DynamicImport I am harlibrary in instanceAdd, %d + %d = %d', a, b, c); 28 return c; 29 } 30} 31 32export function addHarlibrary(a:number, b:number):number { 33 let c = a + b; 34 console.info('DynamicImport I am harlibrary in addHarlibrary, %d + %d = %d', a, b, c); 35 return c; 36} 37``` 38 39```typescript 40// harlibrary's Index.ets 41export { Calc, addHarlibrary } from './src/main/ets/utils/Calc' 42``` 43 44```json5 45// HAP's oh-package.json5 46"dependencies": { 47 "harlibrary": "file:../harlibrary" 48} 49``` 50 51```typescript 52// HAP's src/main/ets/pages/Index.ets 53import('harlibrary').then((ns:ESObject) => { 54 ns.Calc.staticAdd(8, 9); // Call the static member function staticAdd(). 55 let calc:ESObject = new ns.Calc(); // Instantiate the class Calc. 56 calc.instanceAdd(10, 11); // Call the instance member function instanceAdd(). 57 ns.addHarlibrary(6, 7); // Call the global function addHarlibrary(). 58 59 // Reflection using class, member function, and method names as strings. 60 let className = 'Calc'; 61 let methodName = 'instanceAdd'; 62 let staticMethod = 'staticAdd'; 63 let functionName = 'addHarlibrary'; 64 ns[className][staticMethod](12, 13); // Call the static member function staticAdd(). 65 let calc1:ESObject = new ns[className](); // Instantiate the class Calc. 66 calc1[methodName](14, 15); // Call the instance member function instanceAdd(). 67 ns[functionName](16, 17); // Call the global function addHarlibrary(). 68}); 69``` 70 71## Implementation of Dynamic Import 72A dynamic import expression accepts a constant or variable as its argument. 73The following table lists the specifications of dynamic import. 74 75| Scenario| Module Specifier | Description | 76| :------------- | :----------------------------- | :------------------------------------------------------- | 77| Local module | File path | The path must start with **./** or **../**. | 78| Local module | HSP module name | - | 79| Local module | HSP module file path | Currently, dynamic imports with constants are supported, but not ones with variables.| 80| Local module | HAR module name | - | 81| Local module | HAR module file path | Currently, dynamic imports with constants are supported, but not ones with variables.| 82| Remote module | Remote HAR module name | - | 83| Remote module | ohpm package name | - | 84| API | @system.* | - | 85| API | @ohos.* | - | 86| API | @arkui-x.* | - | 87| Native library module | libNativeLibrary.so| - | 88 89Notes: 90 911. Module names used in all imports are the aliases defined under **dependencies** in the **oh-package.json5** file. 922. It is recommended that the alias configured under **dependencies** be the same as the values of **moduleName** and **packageName**, both of which indicate the name of the module to import. **moduleName** is set in the **module.json5** file of the module, and **packageName** is set in the **oh-package.json5** file. 933. Importing a module by name is importing the module's entry file, generally **index.ets/ts**. 94 95## Key Points in Dynamic Import Implementation 96 97### Dynamic Imports with Constant Expressions 98 99Dynamic imports with constant expressions refer to scenarios where the input to **import** is a constant. The following examples show how to use this type of dynamic import to import a module or API into a HAP module. 100 101Note: In the examples, the paths, such as the path to **Index.ets**, are set based on the current DevEco Studio module configuration and are subject to change. 102 103- **HAP dynamically imports a HAR module using a constant module name** 104 105 ```typescript 106 // HAR's Index.ets 107 export function add(a:number, b:number):number { 108 let c = a + b; 109 console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c); 110 return c; 111 } 112 ``` 113 114 ```typescript 115 // HAP's src/main/ets/pages/Index.ets 116 import('myHar').then((ns:ESObject) => { 117 console.info(ns.add(3, 5)); 118 }); 119 ``` 120 121 ```json5 122 // HAP's oh-package.json5 123 "dependencies": { 124 "myHar": "file:../myHar" 125 } 126 ``` 127 128- **HAP dynamically imports a HAR module using a constant file path** 129 130 ```typescript 131 // HAR's Index.ets 132 export function add(a:number, b:number):number { 133 let c = a + b; 134 console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c); 135 return c; 136 } 137 ``` 138 139 ```typescript 140 // HAP's src/main/ets/pages/Index.ets 141 import('myHar/Index').then((ns:ESObject) => { 142 console.info(ns.add(3, 5)); 143 }); 144 ``` 145 146 ```json5 147 // HAP's oh-package.json5 148 "dependencies": { 149 "myHar": "file:../myHar" 150 } 151 ``` 152 153- **HAP dynamically imports an HSP module using a constant module name** 154 155 ```typescript 156 // HSP's Index.ets 157 export function add(a:number, b:number):number { 158 let c = a + b; 159 console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c); 160 return c; 161 } 162 ``` 163 164 ```typescript 165 // HAP's src/main/ets/pages/Index.ets 166 import('myHsp').then((ns:ESObject) => { 167 console.info(ns.add(3, 5)); 168 }); 169 ``` 170 171 ```json5 172 // HAP's oh-package.json5 173 "dependencies": { 174 "myHsp": "file:../myHsp" 175 } 176 ``` 177 178- **HAP dynamically imports an HSP module using a constant file path** 179 180 ```typescript 181 // HSP's Index.ets 182 export function add(a:number, b:number):number { 183 let c = a + b; 184 console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c); 185 return c; 186 } 187 ``` 188 189 ```typescript 190 // HAP's src/main/ets/pages/Index.ets 191 import('myHsp/Index').then((ns:ESObject) => { 192 console.info(ns.add(3, 5)); 193 }); 194 ``` 195 196 ```json5 197 // HAP's oh-package.json5 198 "dependencies": { 199 "myHsp": "file:../myHsp" 200 } 201 ``` 202 203- **HAP dynamically imports a remote HAR module using a constant module name** 204 205 ```typescript 206 // HAP's src/main/ets/pages/Index.ets 207 import('@ohos/crypto-js').then((ns:ESObject) => { 208 console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456)); 209 }); 210 ``` 211 212 ```json5 213 // HAP's oh-package.json5 214 "dependencies": { 215 "@ohos/crypto-js": "2.0.3-rc.0" 216 } 217 ``` 218 219- **HAP dynamically imports an ohpm package using a constant** 220 221 ```typescript 222 // HAP's src/main/ets/pages/Index.ets 223 import('json5').then((ns:ESObject) => { 224 console.info('DynamicImport json5'); 225 }); 226 ``` 227 228 ```json5 229 // HAP's oh-package.json5 230 "dependencies": { 231 "json5": "1.0.2" 232 } 233 ``` 234 235- **HAP dynamically imports its own single file using a constant** 236 237 ```typescript 238 // HAP's src/main/ets/Calc.ets 239 export function add(a:number, b:number):number { 240 let c = a + b; 241 console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c); 242 return c; 243 } 244 ``` 245 246 ```typescript 247 // HAP's src/main/ets/pages/Index.ets 248 import('../Calc').then((ns:ESObject) => { 249 console.info(ns.add(3, 5)); 250 }); 251 ``` 252 253- **HAP dynamically imports its own native library using a constant** 254 255 ```typescript 256 // libnativeapi.so's index.d.ts 257 export const add: (a:number, b:number) => number; 258 ``` 259 260 ```typescript 261 // HAP's src/main/ets/pages/Index.ets 262 import('libnativeapi.so').then((ns:ESObject) => { 263 console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3)); 264 }); 265 ``` 266 267 ```json5 268 // HAP's oh-package.json5 269 "dependencies": { 270 "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi" 271 } 272 ``` 273 274- **HAP dynamically imports APIs using a constant** 275 276 ```typescript 277 // HAP's src/main/ets/pages/Index.ets 278 import('@system.app').then((ns:ESObject) => { ns.default.terminate(); }); 279 import('@system.router').then((ns:ESObject) => { ns.default.clear(); }); 280 import('@ohos.curves').then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); }); 281 import('@ohos.matrix4').then((ns:ESObject) => { ns.default.identity(); }); 282 import('@ohos.hilog').then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); }); 283 ``` 284 285### Dynamic Imports with Variable Expressions 286 287In DevEco Studio, module dependencies are configured through **dependencies** in the **oh-package.json5** file. By default, all modules listed under **dependencies** are installed (for local modules) or downloaded (for remote modules), but are not built. During a HAP/HSP build, the dependency relationship is searched from the entry file (generally **Index.ets/ts**), and only the dependencies found are added to the build. 288During compilation, static imports and dynamic imports with constant expressions can be identified and parsed by the packaging tool rollup and its plug-ins. This means that the related dependencies can be added to the dependency tree, participate in the build process, and finally generate Ark bytecode. However, dynamic imports with variable expressions cannot be resolved at compile-time because their values may depend on runtime calculations or external inputs. To add these dependencies to the build process, add **runtimeOnly** under **buildOption** and set it to the actual module name or file path pertaining to the variable. 289 290**Schema configuration format of the runtimeOnly field** 291 292If you are using dynamic imports with variable expressions to import modules or files, but not APIs, you need to add the **runtimeOnly** field under **buildOption** in the **build-profile.json5** file of the HAP/HSP/HAR module. 293The following are some examples. 294 295```typescript 296// Dynamically import a module based on the module name myHar. 297let harName = 'myHar'; 298import(harName).then(......); 299 300// Dynamically import a file of the module itself based on the file path src/main/ets/index.ets. 301let filePath = './Calc'; 302import(filePath).then(......); 303``` 304 305The corresponding **runtimeOnly** configuration is as follows: 306 307```typescript 308"buildOption": { 309 "arkOptions": { 310 "runtimeOnly": { 311 "packages": [ "myHar" ] // Set the name of the module to dynamically import. It must be the same as the one specified under dependencies. 312 "sources": ["./src/main/ets/utils/Calc.ets"] // Set the path of the file to dynamically import. The path is relative to the build-profile.json5 file of the module. 313 } 314 } 315} 316``` 317 318**packages** of **runtimeOnly**: name of the module to dynamically import. It must be the same as the one specified under **dependencies**. 319**sources** of **runtimeOnly**: path of the file to dynamically import. The path is relative to the **build-profile.json5** file of the module. 320 321**Usage Examples** 322 323- **HAP dynamically imports a HAR module using a variable module name** 324 325 ```typescript 326 // HAR's Index.ets 327 export function add(a:number, b:number):number { 328 let c = a + b; 329 console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c); 330 return c; 331 } 332 ``` 333 ```typescript 334 // HAP's src/main/ets/pages/Index.ets 335 let packageName = 'myHar'; 336 import(packageName).then((ns:ESObject) => { 337 console.info(ns.add(3, 5)); 338 }); 339 ``` 340 ```json5 341 // HAP's oh-package.json5 342 "dependencies": { 343 "myHar": "file:../myHar" 344 } 345 ``` 346 ```json5 347 // HAP's build-profile.json5 348 "buildOption": { 349 "arkOptions": { 350 "runtimeOnly": { 351 "packages": [ 352 "myHar" // Applicable only when a variable is used to dynamically import a module or file. 353 ] 354 } 355 } 356 } 357 ``` 358 359- **HAP dynamically imports an HSP module using a variable module name** 360 361 ```typescript 362 // HSP's Index.ets 363 export function add(a:number, b:number):number { 364 let c = a + b; 365 console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c); 366 return c; 367 } 368 ``` 369 ```typescript 370 // HAP's src/main/ets/pages/Index.ets 371 let packageName = 'myHsp'; 372 import(packageName).then((ns:ESObject) => { 373 console.info(ns.add(3, 5)); 374 }); 375 ``` 376 ```json5 377 // HAP's oh-package.json5 378 "dependencies": { 379 "myHsp": "file:../myHsp" 380 } 381 ``` 382 ```json5 383 // HAP's build-profile.json5 384 "buildOption": { 385 "arkOptions": { 386 "runtimeOnly": { 387 "packages": [ 388 "myHsp" // Applicable only when a variable is used to dynamically import a module. 389 ] 390 } 391 } 392 } 393 ``` 394 395- **HAP dynamically imports a remote HAR module using a variable module name** 396 397 ```typescript 398 // HAP's src/main/ets/pages/Index.ets 399 let packageName = '@ohos/crypto-js'; 400 import(packageName).then((ns:ESObject) => { 401 console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456)); 402 }); 403 ``` 404 ```json5 405 // HAP's oh-package.json5 406 "dependencies": { 407 "@ohos/crypto-js": "2.0.3-rc.0" 408 } 409 ``` 410 ```json5 411 // HAP's build-profile.json5 412 "buildOption": { 413 "arkOptions": { 414 "runtimeOnly": { 415 "packages": [ 416 "@ohos/crypto-js" // Applicable only when a variable is used to dynamically import a module. 417 ] 418 } 419 } 420 } 421 ``` 422 423- **HAP dynamically imports an ohpm package using a variable** 424 425 ```typescript 426 // HAP's src/main/ets/pages/Index.ets 427 let packageName = 'json5'; 428 import(packageName).then((ns:ESObject) => { 429 console.info('DynamicImport json5'); 430 }); 431 ``` 432 ```json5 433 // HAP's oh-package.json5 434 "dependencies": { 435 "json5": "1.0.2" 436 } 437 ``` 438 ```json5 439 // HAP's build-profile.json5 440 "buildOption": { 441 "arkOptions": { 442 "runtimeOnly": { 443 "packages": [ 444 "json5" // Applicable only when a variable is used to dynamically import a module. 445 ] 446 } 447 } 448 } 449 ``` 450 451- **HAP dynamically imports its own single file using a variable** 452 453 ```typescript 454 // HAP's src/main/ets/Calc.ets 455 export function add(a:number, b:number):number { 456 let c = a + b; 457 console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c); 458 return c; 459 } 460 ``` 461 ```typescript 462 // HAP's src/main/ets/pages/Index.ets 463 let filePath = '../Calc'; 464 import(filePath).then((ns:ESObject) => { 465 console.info(ns.add(3, 5)); 466 }); 467 ``` 468 ```json5 469 // HAP's build-profile.json5 470 "buildOption": { 471 "arkOptions": { 472 "runtimeOnly": { 473 "sources": [ 474 "./src/main/ets/Calc.ets" // Applicable only when a variable is used to dynamically import a file of the module itself. 475 ] 476 } 477 } 478 } 479 ``` 480 481- **HAP dynamically imports its own native library using a variable** 482 483 ```typescript 484 // libnativeapi.so's index.d.ts 485 export const add: (a:number, b:number) => number; 486 ``` 487 ```typescript 488 // HAP's src/main/ets/pages/Index.ets 489 let soName = 'libnativeapi.so'; 490 import(soName).then((ns:ESObject) => { 491 console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3)); 492 }); 493 ``` 494 ```json5 495 // HAP's oh-package.json5 496 "dependencies": { 497 "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi" 498 } 499 ``` 500 ```json5 501 // HAP's build-profile.json5 502 "buildOption": { 503 "arkOptions": { 504 "runtimeOnly": { 505 "packages": [ 506 "libnativeapi.so" // Applicable only when a variable is used to dynamically import a module. 507 ] 508 } 509 } 510 } 511 ``` 512 513- **HAP dynamically imports APIs using a variable** 514 515 ```typescript 516 // HAP's src/main/ets/pages/Index.ets 517 let packageName = '@system.app'; 518 import(packageName).then((ns:ESObject) => { ns.default.terminate(); }); 519 packageName = '@system.router'; 520 import(packageName).then((ns:ESObject) => { ns.default.clear(); }); 521 packageName = '@ohos.curves'; 522 import(packageName).then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); }); 523 packageName = '@ohos.matrix4'; 524 import(packageName).then((ns:ESObject) => { ns.default.identity(); }); 525 packageName = '@ohos.hilog'; 526 import(packageName).then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); }); 527 ``` 528You do not need to set **runtimeOnly** when dynamically importing APIs with variables. 529 530### Decoupling Dynamic Imports Between HAR Modules 531When an application contains multiple HAR packages with complex dependency relationships, circular dependencies may occur when configuring dependencies in DevEco Studio. If the dependencies between HAR packages are only through dynamic imports with variable expressions, the direct dependency relationships between HAR packages can be transferred to the HAP/HSP configuration. This decouples the dependencies between HAR packages, as shown in the figure below. 532 533 534 535The figure shows the dependency graph after dependency conversion. 536 537 538 539 540**Constraints** 541- This workaround is only applicable when circular dependencies occur between local HAR packages. 542- The transferred dependencies between HAR packages can only be through dynamic imports with variable expressions, not static imports or dynamic imports with constant expressions. 543- When transferring dependencies, both **dependencies** and **runtimeOnly** configurations must be transferred simultaneously. 544- HSP does not support transferring dependencies. For example, in the chain HAP -> HSP1 -> HSP2 -> HSP3, dependency between HSP2 and HSP3 cannot be transferred to HAP. 545- The entire chain of transferred dependencies must consist only of HAR packages. Dependencies cannot be transferred across HSP packages. An incorrect use is as follows: HAP -> HAR1 -> HAR2 -> HSP -> HAR3 -> HAR4. 546 547 The dependency of HAR1 on HAR2 can be transferred to a HAP, and the dependency of HAR3 on HAR4 can be transferred to an HSP. However, HAR3 or HAR4 cannot be transferred to the HAP. 548 549 550**Usage Examples** 551 552In the following example, HAP dynamically imports HAR package har1, and har1 dynamically imports another HAR package har2 using variables. 553 554```json5 555// HAP's oh-package.json5 556"dependencies": { 557 "har1": "file:../har1" 558} 559``` 560```json5 561// HAP's build-profile.json5 562"buildOption": { 563 "arkOptions": { 564 "runtimeOnly": { 565 "packages": [ 566 "har1" // Applicable only when a variable is used to dynamically import a module. 567 ] 568 } 569 } 570} 571``` 572```typescript 573// HAP's src/main/ets/pages/Index.ets 574let harName = 'har1'; 575import(harName).then((ns:ESObject) => { 576 console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5)); 577}); 578``` 579```json5 580// har1's oh-package.json5 581"dependencies": { 582 "har2": "file:../har2" 583} 584``` 585```json5 586// har1's build-profile.json5 587"buildOption": { 588 "arkOptions": { 589 "runtimeOnly": { 590 "packages": [ 591 "har2" // Applicable only when a variable is used to dynamically import a module. 592 ] 593 } 594 } 595} 596``` 597```typescript 598// har1's Index.ets 599export { addHar1 } from './src/main/ets/utils/Calc' 600``` 601```typescript 602// har1's src/main/ets/utils/Calc.ets 603export function addHar1(a:number, b:number):number { 604 let c = a + b; 605 console.info('DynamicImport I am har1, %d + %d = %d', a, b, c); 606 607 let harName = 'har2'; 608 import(harName).then((ns:ESObject) => { 609 console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5)); 610 }); 611 return c; 612} 613``` 614```typescript 615// har2's Index.ets 616export { addHar2 } from './src/main/ets/utils/Calc' 617``` 618```typescript 619// har2's src/main/ets/utils/Calc.ets 620export function addHar2(a:number, b:number):number { 621 let c = a + b; 622 console.info('DynamicImport I am har2, %d + %d = %d', a, b, c); 623 return c; 624} 625``` 626 627The **dependencies** and **runtimeOnly** configurations of har1 on har2 are transferred to the HAP. In this way, the **dependencies** and **runtimeOnly** configuration of har2 do not need to be configured for har1. 628 629```json5 630// HAP's oh-package.json5 631"dependencies": { 632 "har1": "file:../har1", 633 "har2": "file:../har2" 634} 635``` 636```json5 637// HAP's build-profile.json5 638"buildOption": { 639 "arkOptions": { 640 "runtimeOnly": { 641 "packages": [ 642 "har1", 643 "har2" 644 ] 645 } 646 } 647} 648``` 649```typescript 650// HAP's src/main/ets/pages/Index.ets 651let harName = 'har1'; 652import(harName).then((ns:ESObject) => { 653 console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5)); 654}); 655``` 656```typescript 657// har1's Index.ets 658export { addHar1 } from './src/main/ets/utils/Calc' 659``` 660```typescript 661// har1's src/main/ets/utils/Calc.ets 662export function addHar1(a:number, b:number):number { 663 let c = a + b; 664 console.info('DynamicImport I am har1, %d + %d = %d', a, b, c); 665 666 let harName = 'har2'; 667 import(harName).then((ns:ESObject) => { 668 console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5)); 669 }); 670 return c; 671} 672``` 673```typescript 674// har2's Index.ets 675export { addHar2 } from './src/main/ets/utils/Calc' 676``` 677```typescript 678// har2's src/main/ets/utils/Calc.ets 679export function addHar2(a:number, b:number):number { 680 let c = a + b; 681 console.info('DynamicImport I am har2, %d + %d = %d', a, b, c); 682 return c; 683} 684``` 685