1# Dynamic Import 2 3Dynamic import is a powerful feature that allows for conditional loading and partial reflection, which improves the page load time. You can use it to dynamically load HSP modules, HAR, ohpm packages, and native libraries. Better yet, HAR modules can be decoupled when only variables are dynamically imported between the modules. 4 5## When to Use 6Unlike [static import]](../quick-start/introduction-to-arkts.md#static-import), dynamic import allows you to load a module conditionally or on demand. The following are some cases where you might want to use dynamic import: 7 8* The statically imported module significantly slows the loading of your code, and there is a low likelihood that you will need the module, or you will not need it until a later time. 9* The statically imported modules occupy a large amount of system memory and are unlikely to be used. 10* The module being imported does not exist at load time. 11* The import specifier string needs to be constructed dynamically. (Static import only supports static specifiers.) 12* The module being imported has side effects (which can be understood as code that runs directly in the module), and you do not want those side effects unless some condition is true. 13 14## Bonus 15As aforementioned, in addition to conditional loading, dynamic import can also implement partial reflection. In the following example, the HAP dynamically imports **harlibrary** and calls the static member function **staticAdd()**, member function **instanceAdd()**, and global method **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 member function instanceAdd(). 57 ns.addHarlibrary(6, 7); // Call the global method addHarlibrary(). 58 59 // Call classes, member functions, and methods by name using reflection. 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 member function instanceAdd(). 67 ns[functionName](16, 17); // Call the global method addHarlibrary(). 68}); 69``` 70 71## Implementation 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 import expressions with constants are supported, but not ones with variables.| 80| Local module | HAR module name | - | 81| Local module | HAR module file path | Currently, dynamic import expressions with constants are supported, but not ones with variables.| 82| Remote module | 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. The module names used in imports are the aliases under **dependencies** in the **oh-package.json5** file. 922. It is recommended that the alias 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 point file, generally **index.ets/ts**. 94 95## Implementation Key Points 96 97### Dynamic Import Constant Expression 98 99A dynamic import constant expression is a dynamic import expression that takes in a constant as its argument. The following examples show how to use this type of dynamic import expression 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- **Dynamically importing a HAR module based on the HAR 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- **Dynamically importing a HAR module based on the HAR module 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- **Dynamically importing an HSP module based on the HSP 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- **Dynamically importing an HSP module based on the HSP module 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- **Dynamically importing a remote HAR module based on the HAR 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- **Dynamically importing an ohpm package** 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- **Dynamically importing a file of the HAP module itself** 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- **Dynamically importing a native library of the HAP module itself** 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- **Dynamically importing APIs** 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 Import Variable Expression 286 287In DevEco Studio, the dependencies between modules are configured through **dependencies** in the **oh-package.json5** file. By default, all modules listed under **dependencies** are installed (local modules) or downloaded (remote modules), but are not built. During a HAP/HSP build, the dependency relationship is searched from the entry point file (generally **Index.ets/ts**), and only the dependencies found are added to the build. 288At compile time, static imports and dynamic import 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. As for dynamic import variable expressions, since the variable value may need to be calculated or obtained from an external source, it cannot be determined at compile time; as a result, the related dependencies cannot participate in the build process. 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**1. Schema configuration format of the runtimeOnly field** 291 292If you are using a dynamic import variable expression 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**2. Examples** 322 323- **Dynamically importing a HAR module based on the HAR 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- **Dynamically importing an HSP module based on the HSP 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- **Dynamically importing a remote HAR module based on the HAR 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- **Dynamically importing an ohpm package** 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- **Dynamically importing a file of the HAP module itself** 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- **Dynamically importing a native library of the HAP module itself** 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- **Dynamically importing APIs** 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 Between HAR modules with Dynamic Import 531When an application contains multiple HAR modules, and the dependency between the modules are complex, configuring their dependencies in DevEco Studio can be challenging and, if not handled carefully, can lead to cyclic dependencies. To simplify dependency management, if only variables are dynamically imported between HAR modules, you can convert dependency between HAR modules into dependency between HAR modules and HAP/HSP modules. In this way, the HAR modules are decoupled. The figure shows the dependency graph before dependency conversion. 532 533 534 535The figure shows the dependency graph after dependency conversion. 536 537 538 539 540**1. Constraints** 541- Dependency conversion is applicable only when cyclic dependency is formed between local HAR modules. 542- In HAR modules for which you want to convert dependency, only dynamic import variable expressions are allowed, but not static import or dynamic import constant expressions. 543- When converting dependencies, you must transfer both **dependencies** and **runtimeOnly**. 544- Dependency conversion does not work for HSP modules. For example, in the case of HAP -> HSP1 -> HSP2 -> HSP3, dependency between HSP2 and HSP3 cannot be converted into dependency with the HAP. 545- Only HAR modules are allowed throughout the dependency conversion chain. In other words, no HSP module is allowed between HAR modules. An incorrect use is as follows: HAP -> HAR1 -> HAR2 -> HSP -> HAR3 -> HAR4. 546 547 The dependency of HAR 1 on HAR 2 can be transferred to a HAP, and the dependency of HAR 3 on HAR 4 can be transferred to an HSP. However, HAR3 or HAR4 cannot be transferred to the HAP. 548 549 550**2. Examples** 551 552In the following example, the HAP dynamically imports HAR module har1 based on the module name variable, and har1 dynamically imports another HAR module har2 based on the module name variable. 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