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 the static member function **staticAdd()**, instance member function **instanceAdd()**, and global function **addHarLibrary()** of the **Calc** class. 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 method 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 | - | 80| Local module | HAR module name | - | 81| Local module | HAR module file path | - | 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 89>**NOTE** 90> 91> 1. Module names used in all imports are the aliases defined under **dependencies** in the **oh-package.json5** file. 92> 2. 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. 93> 3. 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 APIs of other modules 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 // You can use await to process dynamic import. (It must be used in an async function.) 121 async function asyncDynamicImport() { 122 let ns:ESObject = await import('myhar'); 123 console.info(ns.add(3, 5)); 124 } 125 ``` 126 127 ```json5 128 // HAP's oh-package.json5 129 "dependencies": { 130 "myhar": "file:../myhar" 131 } 132 ``` 133 134- **HAP dynamically imports a HAR module using a constant file path** 135 136 ```typescript 137 // HAR's Index.ets 138 export function add(a:number, b:number):number { 139 let c = a + b; 140 console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c); 141 return c; 142 } 143 ``` 144 145 ```typescript 146 // HAP's src/main/ets/pages/Index.ets 147 import('myhar/Index').then((ns:ESObject) => { 148 console.info(ns.add(3, 5)); 149 }); 150 ``` 151 152 ```json5 153 // HAP's oh-package.json5 154 "dependencies": { 155 "myhar": "file:../myhar" 156 } 157 ``` 158 159- **HAP dynamically imports an HSP module using a constant module name** 160 161 ```typescript 162 // HSP's Index.ets 163 export function add(a:number, b:number):number { 164 let c = a + b; 165 console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c); 166 return c; 167 } 168 ``` 169 170 ```typescript 171 // HAP's src/main/ets/pages/Index.ets 172 import('myHsp').then((ns:ESObject) => { 173 console.info(ns.add(3, 5)); 174 }); 175 ``` 176 177 ```json5 178 // HAP's oh-package.json5 179 "dependencies": { 180 "myHsp": "file:../myHsp" 181 } 182 ``` 183 184- **HAP dynamically imports an HSP module using a constant file path** 185 186 ```typescript 187 // HSP's Index.ets 188 export function add(a:number, b:number):number { 189 let c = a + b; 190 console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c); 191 return c; 192 } 193 ``` 194 195 ```typescript 196 // HAP's src/main/ets/pages/Index.ets 197 import('myHsp/Index').then((ns:ESObject) => { 198 console.info(ns.add(3, 5)); 199 }); 200 ``` 201 202 ```json5 203 // HAP's oh-package.json5 204 "dependencies": { 205 "myHsp": "file:../myHsp" 206 } 207 ``` 208 209- **HAP dynamically imports a remote HAR module using a constant module name** 210 211 ```typescript 212 // HAP's src/main/ets/pages/Index.ets 213 import('@ohos/crypto-js').then((ns:ESObject) => { 214 console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456)); 215 }); 216 ``` 217 218 ```json5 219 // HAP's oh-package.json5 220 "dependencies": { 221 "@ohos/crypto-js": "2.0.3-rc.0" 222 } 223 ``` 224 225- **HAP dynamically imports an ohpm package using a constant** 226 227 ```typescript 228 // HAP's src/main/ets/pages/Index.ets 229 import('json5').then((ns:ESObject) => { 230 console.info('DynamicImport json5'); 231 }); 232 ``` 233 234 ```json5 235 // HAP's oh-package.json5 236 "dependencies": { 237 "json5": "1.0.2" 238 } 239 ``` 240 241- **HAP dynamically imports its own single file using a constant** 242 243 ```typescript 244 // HAP's src/main/ets/Calc.ets 245 export function add(a:number, b:number):number { 246 let c = a + b; 247 console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c); 248 return c; 249 } 250 ``` 251 252 ```typescript 253 // HAP's src/main/ets/pages/Index.ets 254 import('../Calc').then((ns:ESObject) => { 255 console.info(ns.add(3, 5)); 256 }); 257 ``` 258 259- **HAP dynamically imports its own native library using a constant** 260 261 ```typescript 262 // libnativeapi.so's index.d.ts 263 export const add: (a:number, b:number) => number; 264 ``` 265 266 ```typescript 267 // HAP's src/main/ets/pages/Index.ets 268 import('libnativeapi.so').then((ns:ESObject) => { 269 console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3)); 270 }); 271 ``` 272 273 ```json5 274 // HAP's oh-package.json5 275 "dependencies": { 276 "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi" 277 } 278 ``` 279 280- **HAP dynamically imports APIs using a constant** 281 282 ```typescript 283 // HAP's src/main/ets/pages/Index.ets 284 import('@system.app').then((ns:ESObject) => { ns.default.terminate(); }); 285 import('@system.router').then((ns:ESObject) => { ns.default.clear(); }); 286 import('@ohos.curves').then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); }); 287 import('@ohos.matrix4').then((ns:ESObject) => { ns.default.identity(); }); 288 import('@ohos.hilog').then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); }); 289 ``` 290 291### Dynamic Imports with Variable Expressions 292 293In 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. 294During 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. 295 296**Schema configuration format of the runtimeOnly field** 297 298If 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. The following are some examples. 299 300```typescript 301// Dynamically import a module based on the module name myhar. 302let harName = 'myhar'; 303import(harName).then((obj: ESObject) => { 304 console.info('DynamicImport I am a har'); 305} 306 307// Dynamically import a file of the module itself based on the file path src/main/ets/index.ets. 308let filePath = './Calc'; 309import(filePath).then((obj: ESObject) => { 310 console.info('DynamicImport I am a file'); 311} 312``` 313 314The corresponding **runtimeOnly** configuration is as follows: 315 316```json 317"buildOption": { 318 "arkOptions": { 319 "runtimeOnly": { 320 "packages": [ "myhar" ] // Set the name of the module to dynamically import. It must be the same as the one specified under dependencies. 321 "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. 322 } 323 } 324} 325``` 326 327**packages** of **runtimeOnly**: name of the module to dynamically import. It must be the same as the one specified under **dependencies**. 328**sources** of **runtimeOnly**: path of the file to dynamically import. The path is relative to the **build-profile.json5** file of the module. 329 330**Usage Examples** 331 332- **HAP dynamically imports a HAR module using a variable module name** 333 334 ```typescript 335 // HAR's Index.ets 336 export function add(a:number, b:number):number { 337 let c = a + b; 338 console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c); 339 return c; 340 } 341 ``` 342 ```typescript 343 // HAP's src/main/ets/pages/Index.ets 344 let packageName = 'myhar'; 345 import(packageName).then((ns:ESObject) => { 346 console.info(ns.add(3, 5)); 347 }); 348 ``` 349 ```json5 350 // HAP's oh-package.json5 351 "dependencies": { 352 "myhar": "file:../myhar" 353 } 354 ``` 355 ```json5 356 // HAP's build-profile.json5 357 "buildOption": { 358 "arkOptions": { 359 "runtimeOnly": { 360 "packages": [ 361 "myhar" // Applicable only when a variable is used to dynamically import a module. 362 ] 363 } 364 } 365 } 366 ``` 367 368- **HAP dynamically imports an HSP module using a variable module name** 369 370 ```typescript 371 // HSP's Index.ets 372 export function add(a:number, b:number):number { 373 let c = a + b; 374 console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c); 375 return c; 376 } 377 ``` 378 ```typescript 379 // HAP's src/main/ets/pages/Index.ets 380 let packageName = 'myHsp'; 381 import(packageName).then((ns:ESObject) => { 382 console.info(ns.add(3, 5)); 383 }); 384 ``` 385 ```json5 386 // HAP's oh-package.json5 387 "dependencies": { 388 "myHsp": "file:../myHsp" 389 } 390 ``` 391 ```json5 392 // HAP's build-profile.json5 393 "buildOption": { 394 "arkOptions": { 395 "runtimeOnly": { 396 "packages": [ 397 "myHsp" // Applicable only when a variable is used to dynamically import a module. 398 ] 399 } 400 } 401 } 402 ``` 403 404- **HAP dynamically imports a remote HAR module using a variable module name** 405 406 ```typescript 407 // HAP's src/main/ets/pages/Index.ets 408 let packageName = '@ohos/crypto-js'; 409 import(packageName).then((ns:ESObject) => { 410 console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456)); 411 }); 412 ``` 413 ```json5 414 // HAP's oh-package.json5 415 "dependencies": { 416 "@ohos/crypto-js": "2.0.3-rc.0" 417 } 418 ``` 419 ```json5 420 // HAP's build-profile.json5 421 "buildOption": { 422 "arkOptions": { 423 "runtimeOnly": { 424 "packages": [ 425 "@ohos/crypto-js" // Applicable only when a variable is used to dynamically import a module. 426 ] 427 } 428 } 429 } 430 ``` 431 432- **HAP dynamically imports an ohpm package using a variable** 433 434 ```typescript 435 // HAP's src/main/ets/pages/Index.ets 436 let packageName = 'json5'; 437 import(packageName).then((ns:ESObject) => { 438 console.info('DynamicImport json5'); 439 }); 440 ``` 441 ```json5 442 // HAP's oh-package.json5 443 "dependencies": { 444 "json5": "1.0.2" 445 } 446 ``` 447 ```json5 448 // HAP's build-profile.json5 449 "buildOption": { 450 "arkOptions": { 451 "runtimeOnly": { 452 "packages": [ 453 "json5" // Applicable only when a variable is used to dynamically import a module. 454 ] 455 } 456 } 457 } 458 ``` 459 460- **HAP dynamically imports its own single file using a variable** 461 462 ```typescript 463 // HAP's src/main/ets/Calc.ets 464 export function add(a:number, b:number):number { 465 let c = a + b; 466 console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c); 467 return c; 468 } 469 ``` 470 ```typescript 471 // HAP's src/main/ets/pages/Index.ets 472 let filePath = '../Calc'; 473 import(filePath).then((ns:ESObject) => { 474 console.info(ns.add(3, 5)); 475 }); 476 ``` 477 ```json5 478 // HAP's build-profile.json5 479 "buildOption": { 480 "arkOptions": { 481 "runtimeOnly": { 482 "sources": [ 483 "./src/main/ets/Calc.ets" // Applicable only when a variable is used to dynamically import a file of the module itself. 484 ] 485 } 486 } 487 } 488 ``` 489 490- **HAP dynamically imports its own native library using a variable** 491 492 ```typescript 493 // libnativeapi.so's index.d.ts 494 export const add: (a:number, b:number) => number; 495 ``` 496 ```typescript 497 // HAP's src/main/ets/pages/Index.ets 498 let soName = 'libnativeapi.so'; 499 import(soName).then((ns:ESObject) => { 500 console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3)); 501 }); 502 ``` 503 ```json5 504 // HAP's oh-package.json5 505 "dependencies": { 506 "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi" 507 } 508 ``` 509 ```json5 510 // HAP's build-profile.json5 511 "buildOption": { 512 "arkOptions": { 513 "runtimeOnly": { 514 "packages": [ 515 "libnativeapi.so" // Applicable only when a variable is used to dynamically import a module. 516 ] 517 } 518 } 519 } 520 ``` 521 522- **HAP dynamically imports APIs using a variable** 523 524 ```typescript 525 // HAP's src/main/ets/pages/Index.ets 526 let packageName = '@system.app'; 527 import(packageName).then((ns:ESObject) => { ns.default.terminate(); }); 528 packageName = '@system.router'; 529 import(packageName).then((ns:ESObject) => { ns.default.clear(); }); 530 packageName = '@ohos.curves'; 531 import(packageName).then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); }); 532 packageName = '@ohos.matrix4'; 533 import(packageName).then((ns:ESObject) => { ns.default.identity(); }); 534 packageName = '@ohos.hilog'; 535 import(packageName).then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); }); 536 ``` 537You do not need to set **runtimeOnly** when dynamically importing APIs with variables. 538 539### Decoupling Dynamic Imports Between HAR Modules 540When 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. 541 542 543 544The figure shows the dependency graph after dependency conversion. 545 546 547 548 549**Constraints** 550- This workaround is only applicable when circular dependencies occur between local HAR packages. 551- The transferred dependencies between HAR packages can only be through dynamic imports with variable expressions, not static imports or dynamic imports with constant expressions. 552- When transferring dependencies, both **dependencies** and **runtimeOnly** configurations must be transferred simultaneously. 553- 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. 554- The entire chain of transferred dependencies must consist only of HAR packages. Dependencies cannot be transferred across HSP packages. For example, in the chain HAP-> HAR1 -> HAR2 -> HSP -> HAR3 -> HAR4, the dependency of HAR1 on HAR2 can be transferred to HAP, and the dependency of HAR3 on HAR4 can be transferred to HSP. However, HAR3 or HAR4 cannot be transferred to HAP. 555- If there are references to other project modules, remote packages, or integrated HSP packages, you must ensure that the **useNormalizedOHMUrl** configuration is consistent and set to either **true** or **false**. Failure to do so may result in runtime errors such as **Cannot find dynamic-import module library**. 556 557 558**Usage Examples** 559 560In the following example, HAP dynamically imports HAR package har1, and har1 dynamically imports another HAR package har2 using variables. 561 562```json5 563// HAP's oh-package.json5 564"dependencies": { 565 "har1": "file:../har1" 566} 567``` 568```json5 569// HAP's build-profile.json5 570"buildOption": { 571 "arkOptions": { 572 "runtimeOnly": { 573 "packages": [ 574 "har1" // Applicable only when a variable is used to dynamically import a module. 575 ] 576 } 577 } 578} 579``` 580```typescript 581// HAP's src/main/ets/pages/Index.ets 582let harName = 'har1'; 583import(harName).then((ns:ESObject) => { 584 console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5)); 585}); 586``` 587```json5 588// har1's oh-package.json5 589"dependencies": { 590 "har2": "file:../har2" 591} 592``` 593```json5 594// har1's build-profile.json5 595"buildOption": { 596 "arkOptions": { 597 "runtimeOnly": { 598 "packages": [ 599 "har2" // Applicable only when a variable is used to dynamically import a module. 600 ] 601 } 602 } 603} 604``` 605```typescript 606// har1's Index.ets 607export { addHar1 } from './src/main/ets/utils/Calc' 608``` 609```typescript 610// har1's src/main/ets/utils/Calc.ets 611export function addHar1(a:number, b:number):number { 612 let c = a + b; 613 console.info('DynamicImport I am har1, %d + %d = %d', a, b, c); 614 615 let harName = 'har2'; 616 import(harName).then((ns:ESObject) => { 617 console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5)); 618 }); 619 return c; 620} 621``` 622```typescript 623// har2's Index.ets 624export { addHar2 } from './src/main/ets/utils/Calc' 625``` 626```typescript 627// har2's src/main/ets/utils/Calc.ets 628export function addHar2(a:number, b:number):number { 629 let c = a + b; 630 console.info('DynamicImport I am har2, %d + %d = %d', a, b, c); 631 return c; 632} 633``` 634 635The **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. 636 637```json5 638// HAP's oh-package.json5 639"dependencies": { 640 "har1": "file:../har1", 641 "har2": "file:../har2" 642} 643``` 644```json5 645// HAP's build-profile.json5 646"buildOption": { 647 "arkOptions": { 648 "runtimeOnly": { 649 "packages": [ 650 "har1", 651 "har2" 652 ] 653 } 654 } 655} 656``` 657```typescript 658// HAP's src/main/ets/pages/Index.ets 659let harName = 'har1'; 660import(harName).then((ns:ESObject) => { 661 console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5)); 662}); 663``` 664```typescript 665// har1's Index.ets 666export { addHar1 } from './src/main/ets/utils/Calc' 667``` 668```typescript 669// har1's src/main/ets/utils/Calc.ets 670export function addHar1(a:number, b:number):number { 671 let c = a + b; 672 console.info('DynamicImport I am har1, %d + %d = %d', a, b, c); 673 674 let harName = 'har2'; 675 import(harName).then((ns:ESObject) => { 676 console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5)); 677 }); 678 return c; 679} 680``` 681```typescript 682// har2's Index.ets 683export { addHar2 } from './src/main/ets/utils/Calc' 684``` 685```typescript 686// har2's src/main/ets/utils/Calc.ets 687export function addHar2(a:number, b:number):number { 688 let c = a + b; 689 console.info('DynamicImport I am har2, %d + %d = %d', a, b, c); 690 return c; 691} 692``` 693