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 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 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. The following are some examples. 293 294```typescript 295// Dynamically import a module based on the module name myHar. 296let harName = 'myHar'; 297import(harName).then(......); 298 299// Dynamically import a file of the module itself based on the file path src/main/ets/index.ets. 300let filePath = './Calc'; 301import(filePath).then(......); 302``` 303 304The corresponding **runtimeOnly** configuration is as follows: 305 306```typescript 307"buildOption": { 308 "arkOptions": { 309 "runtimeOnly": { 310 "packages": [ "myHar" ] // Set the name of the module to dynamically import. It must be the same as the one specified under dependencies. 311 "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. 312 } 313 } 314} 315``` 316 317**packages** of **runtimeOnly**: name of the module to dynamically import. It must be the same as the one specified under **dependencies**. 318**sources** of **runtimeOnly**: path of the file to dynamically import. The path is relative to the **build-profile.json5** file of the module. 319 320**Usage Examples** 321 322- **HAP dynamically imports a HAR module using a variable module name** 323 324 ```typescript 325 // HAR's Index.ets 326 export function add(a:number, b:number):number { 327 let c = a + b; 328 console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c); 329 return c; 330 } 331 ``` 332 ```typescript 333 // HAP's src/main/ets/pages/Index.ets 334 let packageName = 'myHar'; 335 import(packageName).then((ns:ESObject) => { 336 console.info(ns.add(3, 5)); 337 }); 338 ``` 339 ```json5 340 // HAP's oh-package.json5 341 "dependencies": { 342 "myHar": "file:../myHar" 343 } 344 ``` 345 ```json5 346 // HAP's build-profile.json5 347 "buildOption": { 348 "arkOptions": { 349 "runtimeOnly": { 350 "packages": [ 351 "myHar" // Applicable only when a variable is used to dynamically import a module or file. 352 ] 353 } 354 } 355 } 356 ``` 357 358- **HAP dynamically imports an HSP module using a variable module name** 359 360 ```typescript 361 // HSP's Index.ets 362 export function add(a:number, b:number):number { 363 let c = a + b; 364 console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c); 365 return c; 366 } 367 ``` 368 ```typescript 369 // HAP's src/main/ets/pages/Index.ets 370 let packageName = 'myHsp'; 371 import(packageName).then((ns:ESObject) => { 372 console.info(ns.add(3, 5)); 373 }); 374 ``` 375 ```json5 376 // HAP's oh-package.json5 377 "dependencies": { 378 "myHsp": "file:../myHsp" 379 } 380 ``` 381 ```json5 382 // HAP's build-profile.json5 383 "buildOption": { 384 "arkOptions": { 385 "runtimeOnly": { 386 "packages": [ 387 "myHsp" // Applicable only when a variable is used to dynamically import a module. 388 ] 389 } 390 } 391 } 392 ``` 393 394- **HAP dynamically imports a remote HAR module using a variable module name** 395 396 ```typescript 397 // HAP's src/main/ets/pages/Index.ets 398 let packageName = '@ohos/crypto-js'; 399 import(packageName).then((ns:ESObject) => { 400 console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456)); 401 }); 402 ``` 403 ```json5 404 // HAP's oh-package.json5 405 "dependencies": { 406 "@ohos/crypto-js": "2.0.3-rc.0" 407 } 408 ``` 409 ```json5 410 // HAP's build-profile.json5 411 "buildOption": { 412 "arkOptions": { 413 "runtimeOnly": { 414 "packages": [ 415 "@ohos/crypto-js" // Applicable only when a variable is used to dynamically import a module. 416 ] 417 } 418 } 419 } 420 ``` 421 422- **HAP dynamically imports an ohpm package using a variable** 423 424 ```typescript 425 // HAP's src/main/ets/pages/Index.ets 426 let packageName = 'json5'; 427 import(packageName).then((ns:ESObject) => { 428 console.info('DynamicImport json5'); 429 }); 430 ``` 431 ```json5 432 // HAP's oh-package.json5 433 "dependencies": { 434 "json5": "1.0.2" 435 } 436 ``` 437 ```json5 438 // HAP's build-profile.json5 439 "buildOption": { 440 "arkOptions": { 441 "runtimeOnly": { 442 "packages": [ 443 "json5" // Applicable only when a variable is used to dynamically import a module. 444 ] 445 } 446 } 447 } 448 ``` 449 450- **HAP dynamically imports its own single file using a variable** 451 452 ```typescript 453 // HAP's src/main/ets/Calc.ets 454 export function add(a:number, b:number):number { 455 let c = a + b; 456 console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c); 457 return c; 458 } 459 ``` 460 ```typescript 461 // HAP's src/main/ets/pages/Index.ets 462 let filePath = '../Calc'; 463 import(filePath).then((ns:ESObject) => { 464 console.info(ns.add(3, 5)); 465 }); 466 ``` 467 ```json5 468 // HAP's build-profile.json5 469 "buildOption": { 470 "arkOptions": { 471 "runtimeOnly": { 472 "sources": [ 473 "./src/main/ets/Calc.ets" // Applicable only when a variable is used to dynamically import a file of the module itself. 474 ] 475 } 476 } 477 } 478 ``` 479 480- **HAP dynamically imports its own native library using a variable** 481 482 ```typescript 483 // libnativeapi.so's index.d.ts 484 export const add: (a:number, b:number) => number; 485 ``` 486 ```typescript 487 // HAP's src/main/ets/pages/Index.ets 488 let soName = 'libnativeapi.so'; 489 import(soName).then((ns:ESObject) => { 490 console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3)); 491 }); 492 ``` 493 ```json5 494 // HAP's oh-package.json5 495 "dependencies": { 496 "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi" 497 } 498 ``` 499 ```json5 500 // HAP's build-profile.json5 501 "buildOption": { 502 "arkOptions": { 503 "runtimeOnly": { 504 "packages": [ 505 "libnativeapi.so" // Applicable only when a variable is used to dynamically import a module. 506 ] 507 } 508 } 509 } 510 ``` 511 512- **HAP dynamically imports APIs using a variable** 513 514 ```typescript 515 // HAP's src/main/ets/pages/Index.ets 516 let packageName = '@system.app'; 517 import(packageName).then((ns:ESObject) => { ns.default.terminate(); }); 518 packageName = '@system.router'; 519 import(packageName).then((ns:ESObject) => { ns.default.clear(); }); 520 packageName = '@ohos.curves'; 521 import(packageName).then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); }); 522 packageName = '@ohos.matrix4'; 523 import(packageName).then((ns:ESObject) => { ns.default.identity(); }); 524 packageName = '@ohos.hilog'; 525 import(packageName).then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); }); 526 ``` 527You do not need to set **runtimeOnly** when dynamically importing APIs with variables. 528 529### Decoupling Dynamic Imports Between HAR Modules 530When 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. 531 532 533 534The figure shows the dependency graph after dependency conversion. 535 536 537 538 539**Constraints** 540- This workaround is only applicable when circular dependencies occur between local HAR packages. 541- The transferred dependencies between HAR packages can only be through dynamic imports with variable expressions, not static imports or dynamic imports with constant expressions. 542- When transferring dependencies, both **dependencies** and **runtimeOnly** configurations must be transferred simultaneously. 543- 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. 544- 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. 545 546 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. 547 548 549**Usage Examples** 550 551In the following example, HAP dynamically imports HAR package har1, and har1 dynamically imports another HAR package har2 using variables. 552 553```json5 554// HAP's oh-package.json5 555"dependencies": { 556 "har1": "file:../har1" 557} 558``` 559```json5 560// HAP's build-profile.json5 561"buildOption": { 562 "arkOptions": { 563 "runtimeOnly": { 564 "packages": [ 565 "har1" // Applicable only when a variable is used to dynamically import a module. 566 ] 567 } 568 } 569} 570``` 571```typescript 572// HAP's src/main/ets/pages/Index.ets 573let harName = 'har1'; 574import(harName).then((ns:ESObject) => { 575 console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5)); 576}); 577``` 578```json5 579// har1's oh-package.json5 580"dependencies": { 581 "har2": "file:../har2" 582} 583``` 584```json5 585// har1's build-profile.json5 586"buildOption": { 587 "arkOptions": { 588 "runtimeOnly": { 589 "packages": [ 590 "har2" // Applicable only when a variable is used to dynamically import a module. 591 ] 592 } 593 } 594} 595``` 596```typescript 597// har1's Index.ets 598export { addHar1 } from './src/main/ets/utils/Calc' 599``` 600```typescript 601// har1's src/main/ets/utils/Calc.ets 602export function addHar1(a:number, b:number):number { 603 let c = a + b; 604 console.info('DynamicImport I am har1, %d + %d = %d', a, b, c); 605 606 let harName = 'har2'; 607 import(harName).then((ns:ESObject) => { 608 console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5)); 609 }); 610 return c; 611} 612``` 613```typescript 614// har2's Index.ets 615export { addHar2 } from './src/main/ets/utils/Calc' 616``` 617```typescript 618// har2's src/main/ets/utils/Calc.ets 619export function addHar2(a:number, b:number):number { 620 let c = a + b; 621 console.info('DynamicImport I am har2, %d + %d = %d', a, b, c); 622 return c; 623} 624``` 625 626The **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. 627 628```json5 629// HAP's oh-package.json5 630"dependencies": { 631 "har1": "file:../har1", 632 "har2": "file:../har2" 633} 634``` 635```json5 636// HAP's build-profile.json5 637"buildOption": { 638 "arkOptions": { 639 "runtimeOnly": { 640 "packages": [ 641 "har1", 642 "har2" 643 ] 644 } 645 } 646} 647``` 648```typescript 649// HAP's src/main/ets/pages/Index.ets 650let harName = 'har1'; 651import(harName).then((ns:ESObject) => { 652 console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5)); 653}); 654``` 655```typescript 656// har1's Index.ets 657export { addHar1 } from './src/main/ets/utils/Calc' 658``` 659```typescript 660// har1's src/main/ets/utils/Calc.ets 661export function addHar1(a:number, b:number):number { 662 let c = a + b; 663 console.info('DynamicImport I am har1, %d + %d = %d', a, b, c); 664 665 let harName = 'har2'; 666 import(harName).then((ns:ESObject) => { 667 console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5)); 668 }); 669 return c; 670} 671``` 672```typescript 673// har2's Index.ets 674export { addHar2 } from './src/main/ets/utils/Calc' 675``` 676```typescript 677// har2's src/main/ets/utils/Calc.ets 678export function addHar2(a:number, b:number):number { 679 let c = a + b; 680 console.info('DynamicImport I am har2, %d + %d = %d', a, b, c); 681 return c; 682} 683``` 684