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![Cyclic dependency between HAR modules before dependency conversion](figures/dynamicimport1.png)
534
535The figure shows the dependency graph after dependency conversion.
536
537![Dependency between HAR modules and a HAP after dependency conversion](figures/dynamicimport2.png)
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