1e41f4b71Sopenharmony_ci# Accelerating Web Page Access
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ciWhen the web page loads slowly, you can use the capabilities of pre-connection, preloading, and prefetching POST requests to accelerate the access to the web page.
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci## Preparsing and Preconnecting
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciYou can call [prepareForPageLoad()](../reference/apis-arkweb/js-apis-webview.md#prepareforpageload10) to preparse or preconnect to the page to be loaded.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci  In the following example, the page to be loaded is preconnected in the **onAppear** callback of the **\<Web>** component.
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci```ts
12e41f4b71Sopenharmony_ci// xxx.ets
13e41f4b71Sopenharmony_ciimport { webview } from '@kit.ArkWeb';
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci@Entry
16e41f4b71Sopenharmony_ci@Component
17e41f4b71Sopenharmony_cistruct WebComponent {
18e41f4b71Sopenharmony_ci  webviewController: webview.WebviewController = new webview.WebviewController();
19e41f4b71Sopenharmony_ci
20e41f4b71Sopenharmony_ci  build() {
21e41f4b71Sopenharmony_ci    Column() {
22e41f4b71Sopenharmony_ci      Button('loadData')
23e41f4b71Sopenharmony_ci        .onClick(() => {
24e41f4b71Sopenharmony_ci          if (this.webviewController.accessBackward()) {
25e41f4b71Sopenharmony_ci            this.webviewController.backward();
26e41f4b71Sopenharmony_ci          }
27e41f4b71Sopenharmony_ci        })
28e41f4b71Sopenharmony_ci      Web({ src: 'https://www.example.com/', controller: this.webviewController })
29e41f4b71Sopenharmony_ci        .onAppear(() => {
30e41f4b71Sopenharmony_ci          // The second parameter specifies whether to preconnect to a URL. The value false means that only DNS resolution is conducted on the URL.
31e41f4b71Sopenharmony_ci          // The third parameter indicates the number of sockets to be preconnected. A maximum of six sockets are allowed.
32e41f4b71Sopenharmony_ci          webview.WebviewController.prepareForPageLoad('https://www.example.com/', true, 2);
33e41f4b71Sopenharmony_ci        })
34e41f4b71Sopenharmony_ci    }
35e41f4b71Sopenharmony_ci  }
36e41f4b71Sopenharmony_ci}
37e41f4b71Sopenharmony_ci```
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ciYou can also use [initializeBrowserEngine()](../reference/apis-arkweb/js-apis-webview.md#initializewebengine) to initialize the web kernel in advance, and then call
40e41f4b71Sopenharmony_ci[prepareForPageLoad()](../reference/apis-arkweb/js-apis-webview.md#prepareforpageload10) after the kernel is initialized. This method is applicable to preparsing and preconnecting of the home page.
41e41f4b71Sopenharmony_ci.
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ci  In the following example, the web kernel is initialized in advance and the home page is preconnected in **onCreate** of the UIAbility.
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ci```ts
46e41f4b71Sopenharmony_ci// xxx.ets
47e41f4b71Sopenharmony_ciimport { webview } from '@kit.ArkWeb';
48e41f4b71Sopenharmony_ciimport { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
49e41f4b71Sopenharmony_ci
50e41f4b71Sopenharmony_ciexport default class EntryAbility extends UIAbility {
51e41f4b71Sopenharmony_ci  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
52e41f4b71Sopenharmony_ci    console.log("EntryAbility onCreate");
53e41f4b71Sopenharmony_ci    webview.WebviewController.initializeWebEngine();
54e41f4b71Sopenharmony_ci    // Replace 'https://www.example.com' with the actual URL to be accessed.
55e41f4b71Sopenharmony_ci    webview.WebviewController.prepareForPageLoad("https://www.example.com/", true, 2);
56e41f4b71Sopenharmony_ci    AppStorage.setOrCreate("abilityWant", want);
57e41f4b71Sopenharmony_ci    console.log("EntryAbility onCreate done");
58e41f4b71Sopenharmony_ci  }
59e41f4b71Sopenharmony_ci}
60e41f4b71Sopenharmony_ci```
61e41f4b71Sopenharmony_ci
62e41f4b71Sopenharmony_ci## Prefetching
63e41f4b71Sopenharmony_ci
64e41f4b71Sopenharmony_ciBased on predictions as to what page is to be loaded or visited, you can use [prefetchPage()](../reference/apis-arkweb/js-apis-webview.md#prefetchpage10) for prefetching.
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ciPrefetching downloads all resources required by the page, including the main resources and subresources, but does not execute the JavaScript code of the page. Before calling **prefetchPage()**, you must create a **WebviewController** instance bound to the **\<Web>** component.
67e41f4b71Sopenharmony_ci
68e41f4b71Sopenharmony_ciIn the following example, prefetching of a page is triggered in **onPageEnd**.
69e41f4b71Sopenharmony_ci
70e41f4b71Sopenharmony_ci```ts
71e41f4b71Sopenharmony_ci// xxx.ets
72e41f4b71Sopenharmony_ciimport { webview } from '@kit.ArkWeb';
73e41f4b71Sopenharmony_ci
74e41f4b71Sopenharmony_ci@Entry
75e41f4b71Sopenharmony_ci@Component
76e41f4b71Sopenharmony_cistruct WebComponent {
77e41f4b71Sopenharmony_ci  webviewController: webview.WebviewController = new webview.WebviewController();
78e41f4b71Sopenharmony_ci
79e41f4b71Sopenharmony_ci  build() {
80e41f4b71Sopenharmony_ci    Column() {
81e41f4b71Sopenharmony_ci      Web({ src: 'https://www.example.com/', controller: this.webviewController })
82e41f4b71Sopenharmony_ci        .onPageEnd(() => {
83e41f4b71Sopenharmony_ci          // Prefetch the page at https://www.iana.org/help/example-domains.
84e41f4b71Sopenharmony_ci          this.webviewController.prefetchPage('https://www.iana.org/help/example-domains');
85e41f4b71Sopenharmony_ci        })
86e41f4b71Sopenharmony_ci    }
87e41f4b71Sopenharmony_ci  }
88e41f4b71Sopenharmony_ci}
89e41f4b71Sopenharmony_ci```
90e41f4b71Sopenharmony_ci
91e41f4b71Sopenharmony_ci## Prefetching a POST Request
92e41f4b71Sopenharmony_ci
93e41f4b71Sopenharmony_ciYou can prefetch POST requests in the page that is about to be loaded using the [prefetchResource()](../reference/apis-arkweb/js-apis-webview.md#prefetchresource12) API. At the end of the page load, you can clear the cache of the prefetched requests that are no longer needed using the [clearPrefetchedResource()](../reference/apis-arkweb/js-apis-webview.md#clearprefetchedresource12) API.
94e41f4b71Sopenharmony_ci
95e41f4b71Sopenharmony_ci  The following is an example: In the **onAppear** event of the **\<Web>** component, prefetch the POST request for the page that is about to be loaded; in the **onPageEnd** event, you can clear the cache of the prefetched POST request that is no longer needed.
96e41f4b71Sopenharmony_ci
97e41f4b71Sopenharmony_ci```ts
98e41f4b71Sopenharmony_ci// xxx.ets
99e41f4b71Sopenharmony_ciimport { webview } from '@kit.ArkWeb';
100e41f4b71Sopenharmony_ci
101e41f4b71Sopenharmony_ci@Entry
102e41f4b71Sopenharmony_ci@Component
103e41f4b71Sopenharmony_cistruct WebComponent {
104e41f4b71Sopenharmony_ci  webviewController: webview.WebviewController = new webview.WebviewController();
105e41f4b71Sopenharmony_ci  
106e41f4b71Sopenharmony_ci  build() {
107e41f4b71Sopenharmony_ci    Column() {
108e41f4b71Sopenharmony_ci      Web({ src: "https://www.example.com/", controller: this.webviewController})
109e41f4b71Sopenharmony_ci        .onAppear(() => {
110e41f4b71Sopenharmony_ci          // Replace https://www.example1.com/post?e=f&g=h with the actual URL of the POST request to prefetch.
111e41f4b71Sopenharmony_ci          webview.WebviewController.prefetchResource(
112e41f4b71Sopenharmony_ci            {url:"https://www.example1.com/post?e=f&g=h",
113e41f4b71Sopenharmony_ci              method:"POST",
114e41f4b71Sopenharmony_ci              formData:"a=x&b=y",},
115e41f4b71Sopenharmony_ci            [{headerKey:"c",
116e41f4b71Sopenharmony_ci              headerValue:"z",},],
117e41f4b71Sopenharmony_ci            "KeyX", 500);
118e41f4b71Sopenharmony_ci        })
119e41f4b71Sopenharmony_ci        .onPageEnd(() => {
120e41f4b71Sopenharmony_ci          // Clear the cache of prefetched resources that are no longer used.
121e41f4b71Sopenharmony_ci          webview.WebviewController.clearPrefetchedResource(["KeyX",]);
122e41f4b71Sopenharmony_ci        })
123e41f4b71Sopenharmony_ci    }
124e41f4b71Sopenharmony_ci  }
125e41f4b71Sopenharmony_ci}
126e41f4b71Sopenharmony_ci```
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_ciIf you can predict that a **\<Web>** component is about to load a page or is about to navigate to a page that includes a POST request, you can use [prefetchResource()](../reference/apis-arkweb/js-apis-webview.md#prefetchresource12) to prefetch the POST request for the page.
129e41f4b71Sopenharmony_ci
130e41f4b71Sopenharmony_ci  Here is an example of how you might initiate prefetching of a POST request for a page to visit, in the **onPageEnd** callback:
131e41f4b71Sopenharmony_ci
132e41f4b71Sopenharmony_ci```ts
133e41f4b71Sopenharmony_ci// xxx.ets
134e41f4b71Sopenharmony_ciimport { webview } from '@kit.ArkWeb';
135e41f4b71Sopenharmony_ci
136e41f4b71Sopenharmony_ci@Entry
137e41f4b71Sopenharmony_ci@Component
138e41f4b71Sopenharmony_cistruct WebComponent {
139e41f4b71Sopenharmony_ci  webviewController: webview.WebviewController = new webview.WebviewController();
140e41f4b71Sopenharmony_ci  
141e41f4b71Sopenharmony_ci  build() {
142e41f4b71Sopenharmony_ci    Column() {
143e41f4b71Sopenharmony_ci      Web({ src: 'https://www.example.com/', controller: this.webviewController})
144e41f4b71Sopenharmony_ci        .onPageEnd(() => {
145e41f4b71Sopenharmony_ci          // Replace https://www.example1.com/post?e=f&g=h with the actual URL of the POST request to prefetch.
146e41f4b71Sopenharmony_ci          webview.WebviewController.prefetchResource(
147e41f4b71Sopenharmony_ci            {url:"https://www.example1.com/post?e=f&g=h",
148e41f4b71Sopenharmony_ci              method:"POST",
149e41f4b71Sopenharmony_ci              formData:"a=x&b=y",},
150e41f4b71Sopenharmony_ci            [{headerKey:"c",
151e41f4b71Sopenharmony_ci              headerValue:"z",},],
152e41f4b71Sopenharmony_ci            "KeyX", 500);
153e41f4b71Sopenharmony_ci        })
154e41f4b71Sopenharmony_ci    }
155e41f4b71Sopenharmony_ci  }
156e41f4b71Sopenharmony_ci}
157e41f4b71Sopenharmony_ci```
158e41f4b71Sopenharmony_ci
159e41f4b71Sopenharmony_ciYou can also initialize the ArkWeb engine in advance using the [initializeBrowserEngine()](../reference/apis-arkweb/js-apis-webview.md#initializewebengine) API, and then call [prefetchResource()](../reference/apis-arkweb/js-apis-webview.md#prefetchresource12) to prefetch the POST request for the page that will be loaded soon. This approach is suitable for prefetching POST requests for the home page in advance.
160e41f4b71Sopenharmony_ci
161e41f4b71Sopenharmony_ci  In the following example, the web engine is initialized in advance and the POST request of the home page is preobtained in **onCreate()** of the ability.
162e41f4b71Sopenharmony_ci
163e41f4b71Sopenharmony_ci```ts
164e41f4b71Sopenharmony_ci// xxx.ets
165e41f4b71Sopenharmony_ciimport { webview } from '@kit.ArkWeb';
166e41f4b71Sopenharmony_ciimport { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
167e41f4b71Sopenharmony_ci
168e41f4b71Sopenharmony_ciexport default class EntryAbility extends UIAbility {
169e41f4b71Sopenharmony_ci  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
170e41f4b71Sopenharmony_ci    console.log("EntryAbility onCreate");
171e41f4b71Sopenharmony_ci    webview.WebviewController.initializeWebEngine();
172e41f4b71Sopenharmony_ci    // Replace https://www.example1.com/post?e=f&g=h with the actual URL of the POST request to prefetch.
173e41f4b71Sopenharmony_ci    webview.WebviewController.prefetchResource(
174e41f4b71Sopenharmony_ci      {url:"https://www.example1.com/post?e=f&g=h",
175e41f4b71Sopenharmony_ci        method:"POST",
176e41f4b71Sopenharmony_ci        formData:"a=x&b=y",},
177e41f4b71Sopenharmony_ci      [{headerKey:"c",
178e41f4b71Sopenharmony_ci        headerValue:"z",},],
179e41f4b71Sopenharmony_ci      "KeyX", 500);
180e41f4b71Sopenharmony_ci    AppStorage.setOrCreate("abilityWant", want);
181e41f4b71Sopenharmony_ci    console.log("EntryAbility onCreate done");
182e41f4b71Sopenharmony_ci  }
183e41f4b71Sopenharmony_ci}
184e41f4b71Sopenharmony_ci```
185e41f4b71Sopenharmony_ci
186e41f4b71Sopenharmony_ci## Precompiling for the Compilation Cache
187e41f4b71Sopenharmony_ci
188e41f4b71Sopenharmony_ciYou can use [precompileJavaScript()](../reference/apis-arkweb/js-apis-webview.md#precompilejavascript12) to generate the compilation cache of the script file before page loading.
189e41f4b71Sopenharmony_ci
190e41f4b71Sopenharmony_ciYou are advised to use this function together with dynamic components, use offline **Web** components to generate bytecode caches, and load the service **Web** component at the appropriate time to use the bytecode caches. The example code is as follows:
191e41f4b71Sopenharmony_ci
192e41f4b71Sopenharmony_ci1. First, save **UIContext** to **localStorage** in EntryAbility.
193e41f4b71Sopenharmony_ci
194e41f4b71Sopenharmony_ci   ```ts
195e41f4b71Sopenharmony_ci   // EntryAbility.ets
196e41f4b71Sopenharmony_ci   import { UIAbility } from '@kit.AbilityKit';
197e41f4b71Sopenharmony_ci   import { window } from '@kit.ArkUI';
198e41f4b71Sopenharmony_ci
199e41f4b71Sopenharmony_ci   const localStorage: LocalStorage = new LocalStorage('uiContext');
200e41f4b71Sopenharmony_ci
201e41f4b71Sopenharmony_ci   export default class EntryAbility extends UIAbility {
202e41f4b71Sopenharmony_ci     storage: LocalStorage = localStorage;
203e41f4b71Sopenharmony_ci
204e41f4b71Sopenharmony_ci     onWindowStageCreate(windowStage: window.WindowStage) {
205e41f4b71Sopenharmony_ci       windowStage.loadContent('pages/Index', this.storage, (err, data) => {
206e41f4b71Sopenharmony_ci         if (err.code) {
207e41f4b71Sopenharmony_ci           return;
208e41f4b71Sopenharmony_ci         }
209e41f4b71Sopenharmony_ci
210e41f4b71Sopenharmony_ci         this.storage.setOrCreate<UIContext>("uiContext", windowStage.getMainWindowSync().getUIContext());
211e41f4b71Sopenharmony_ci       });
212e41f4b71Sopenharmony_ci     }
213e41f4b71Sopenharmony_ci   }
214e41f4b71Sopenharmony_ci   ```
215e41f4b71Sopenharmony_ci
216e41f4b71Sopenharmony_ci2. Compile the basic code required of the dynamic components.
217e41f4b71Sopenharmony_ci
218e41f4b71Sopenharmony_ci   ```ts
219e41f4b71Sopenharmony_ci   // DynamicComponent.ets
220e41f4b71Sopenharmony_ci   import { NodeController, BuilderNode, FrameNode, UIContext } from '@kit.ArkUI';
221e41f4b71Sopenharmony_ci
222e41f4b71Sopenharmony_ci   export interface BuilderData {
223e41f4b71Sopenharmony_ci     url: string;
224e41f4b71Sopenharmony_ci     controller: WebviewController;
225e41f4b71Sopenharmony_ci   }
226e41f4b71Sopenharmony_ci
227e41f4b71Sopenharmony_ci   const storage = LocalStorage.getShared();
228e41f4b71Sopenharmony_ci
229e41f4b71Sopenharmony_ci   export class NodeControllerImpl extends NodeController {
230e41f4b71Sopenharmony_ci     private rootNode: BuilderNode<BuilderData[]> | null = null;
231e41f4b71Sopenharmony_ci     private wrappedBuilder: WrappedBuilder<BuilderData[]> | null = null;
232e41f4b71Sopenharmony_ci
233e41f4b71Sopenharmony_ci     constructor(wrappedBuilder: WrappedBuilder<BuilderData[]>) {
234e41f4b71Sopenharmony_ci       super();
235e41f4b71Sopenharmony_ci       this.wrappedBuilder = wrappedBuilder;
236e41f4b71Sopenharmony_ci     }
237e41f4b71Sopenharmony_ci
238e41f4b71Sopenharmony_ci     makeNode(): FrameNode | null {
239e41f4b71Sopenharmony_ci       if (this.rootNode != null) {
240e41f4b71Sopenharmony_ci         return this.rootNode.getFrameNode();
241e41f4b71Sopenharmony_ci       }
242e41f4b71Sopenharmony_ci       return null;
243e41f4b71Sopenharmony_ci     }
244e41f4b71Sopenharmony_ci
245e41f4b71Sopenharmony_ci     initWeb(url: string, controller: WebviewController) {
246e41f4b71Sopenharmony_ci       if(this.rootNode != null) {
247e41f4b71Sopenharmony_ci         return;
248e41f4b71Sopenharmony_ci       }
249e41f4b71Sopenharmony_ci
250e41f4b71Sopenharmony_ci       const uiContext: UIContext = storage.get<UIContext>("uiContext") as UIContext;
251e41f4b71Sopenharmony_ci       if (!uiContext) {
252e41f4b71Sopenharmony_ci         return;
253e41f4b71Sopenharmony_ci       }
254e41f4b71Sopenharmony_ci       this.rootNode = new BuilderNode(uiContext);
255e41f4b71Sopenharmony_ci       this.rootNode.build(this.wrappedBuilder, { url: url, controller: controller });
256e41f4b71Sopenharmony_ci     }
257e41f4b71Sopenharmony_ci   }
258e41f4b71Sopenharmony_ci
259e41f4b71Sopenharmony_ci   export const createNode = (wrappedBuilder: WrappedBuilder<BuilderData[]>, data: BuilderData) => {
260e41f4b71Sopenharmony_ci     const baseNode = new NodeControllerImpl(wrappedBuilder);
261e41f4b71Sopenharmony_ci     baseNode.initWeb(data.url, data.controller);
262e41f4b71Sopenharmony_ci     return baseNode;
263e41f4b71Sopenharmony_ci   }
264e41f4b71Sopenharmony_ci   ```
265e41f4b71Sopenharmony_ci
266e41f4b71Sopenharmony_ci3. Compile the component for generating the bytecode cache. In this example, the local Javascript resource reads the local file in the **rawfile** directory through **readRawFile()**.
267e41f4b71Sopenharmony_ci
268e41f4b71Sopenharmony_ci   ```ts
269e41f4b71Sopenharmony_ci   // PrecompileWebview.ets
270e41f4b71Sopenharmony_ci   import { BuilderData } from "./DynamicComponent";
271e41f4b71Sopenharmony_ci   import { Config, configs } from "./PrecompileConfig";
272e41f4b71Sopenharmony_ci
273e41f4b71Sopenharmony_ci   @Builder
274e41f4b71Sopenharmony_ci   function WebBuilder(data: BuilderData) {
275e41f4b71Sopenharmony_ci     Web({ src: data.url, controller: data.controller })
276e41f4b71Sopenharmony_ci       .onControllerAttached(() => {
277e41f4b71Sopenharmony_ci         precompile(data.controller, configs);
278e41f4b71Sopenharmony_ci       })
279e41f4b71Sopenharmony_ci       .fileAccess(true)
280e41f4b71Sopenharmony_ci   }
281e41f4b71Sopenharmony_ci
282e41f4b71Sopenharmony_ci   export const precompileWebview = wrapBuilder<BuilderData[]>(WebBuilder);
283e41f4b71Sopenharmony_ci
284e41f4b71Sopenharmony_ci   export const precompile = async (controller: WebviewController, configs: Array<Config>) => {
285e41f4b71Sopenharmony_ci     for (const config of configs) {
286e41f4b71Sopenharmony_ci       let content = await readRawFile(config.localPath);
287e41f4b71Sopenharmony_ci
288e41f4b71Sopenharmony_ci       try {
289e41f4b71Sopenharmony_ci         controller.precompileJavaScript(config.url, content, config.options)
290e41f4b71Sopenharmony_ci           .then(errCode => {
291e41f4b71Sopenharmony_ci             console.error("precompile successfully! " + errCode);
292e41f4b71Sopenharmony_ci           }).catch((errCode: number) => {
293e41f4b71Sopenharmony_ci             console.error("precompile failed. " + errCode);
294e41f4b71Sopenharmony_ci         });
295e41f4b71Sopenharmony_ci       } catch (err) {
296e41f4b71Sopenharmony_ci         console.error("precompile failed. " + err.code + " " + err.message);
297e41f4b71Sopenharmony_ci       }
298e41f4b71Sopenharmony_ci     }
299e41f4b71Sopenharmony_ci   }
300e41f4b71Sopenharmony_ci
301e41f4b71Sopenharmony_ci   async function readRawFile(path: string) {
302e41f4b71Sopenharmony_ci     try {
303e41f4b71Sopenharmony_ci       return await getContext().resourceManager.getRawFileContent(path);;
304e41f4b71Sopenharmony_ci     } catch (err) {
305e41f4b71Sopenharmony_ci       return new Uint8Array(0);
306e41f4b71Sopenharmony_ci     }
307e41f4b71Sopenharmony_ci   }
308e41f4b71Sopenharmony_ci   ```
309e41f4b71Sopenharmony_ci
310e41f4b71Sopenharmony_ciJavaScript resources can also be obtained through [Data Request](../reference/apis-network-kit/js-apis-http.md). However, the format of HTTP response header obtained using this method is not standard. Additional steps are required to convert the response header into the standard HTTP response header format before use. If the response header obtained through a network request is **e-tag**, convert it to **E-Tag** before using it.
311e41f4b71Sopenharmony_ci
312e41f4b71Sopenharmony_ci4. Compile the code of the service component.
313e41f4b71Sopenharmony_ci
314e41f4b71Sopenharmony_ci   ```ts
315e41f4b71Sopenharmony_ci   // BusinessWebview.ets
316e41f4b71Sopenharmony_ci   import { BuilderData } from "./DynamicComponent";
317e41f4b71Sopenharmony_ci
318e41f4b71Sopenharmony_ci   @Builder
319e41f4b71Sopenharmony_ci   function WebBuilder(data: BuilderData) {
320e41f4b71Sopenharmony_ci     // The component can be extended as required.
321e41f4b71Sopenharmony_ci     Web({ src: data.url, controller: data.controller })
322e41f4b71Sopenharmony_ci       .cacheMode(CacheMode.Default)
323e41f4b71Sopenharmony_ci   }
324e41f4b71Sopenharmony_ci
325e41f4b71Sopenharmony_ci   export const businessWebview = wrapBuilder<BuilderData[]>(WebBuilder);
326e41f4b71Sopenharmony_ci   ```
327e41f4b71Sopenharmony_ci
328e41f4b71Sopenharmony_ci5. Edit the resource configuration information.
329e41f4b71Sopenharmony_ci
330e41f4b71Sopenharmony_ci   ```ts
331e41f4b71Sopenharmony_ci   // PrecompileConfig.ets
332e41f4b71Sopenharmony_ci   import { webview } from '@kit.ArkWeb'
333e41f4b71Sopenharmony_ci
334e41f4b71Sopenharmony_ci   export interface Config {
335e41f4b71Sopenharmony_ci     url:  string,
336e41f4b71Sopenharmony_ci     localPath: string, // Local resource path.
337e41f4b71Sopenharmony_ci     options: webview.CacheOptions
338e41f4b71Sopenharmony_ci   }
339e41f4b71Sopenharmony_ci
340e41f4b71Sopenharmony_ci   export let configs: Array<Config> = [
341e41f4b71Sopenharmony_ci     {
342e41f4b71Sopenharmony_ci       url: "https://www.example.com/example.js",
343e41f4b71Sopenharmony_ci       localPath: "example.js",
344e41f4b71Sopenharmony_ci       options: {
345e41f4b71Sopenharmony_ci         responseHeaders: [
346e41f4b71Sopenharmony_ci           { headerKey: "E-Tag", headerValue: "aWO42N9P9dG/5xqYQCxsx+vDOoU="},
347e41f4b71Sopenharmony_ci           { headerKey: "Last-Modified", headerValue: "Wed, 21 Mar 2024 10:38:41 GMT"}
348e41f4b71Sopenharmony_ci         ]
349e41f4b71Sopenharmony_ci       }
350e41f4b71Sopenharmony_ci     }
351e41f4b71Sopenharmony_ci   ]
352e41f4b71Sopenharmony_ci   ```
353e41f4b71Sopenharmony_ci
354e41f4b71Sopenharmony_ci6. Use the components on the page.
355e41f4b71Sopenharmony_ci
356e41f4b71Sopenharmony_ci   ```ts
357e41f4b71Sopenharmony_ci   // Index.ets
358e41f4b71Sopenharmony_ci   import { webview } from '@kit.ArkWeb';
359e41f4b71Sopenharmony_ci   import { NodeController } from '@kit.ArkUI';
360e41f4b71Sopenharmony_ci   import { createNode } from "./DynamicComponent"
361e41f4b71Sopenharmony_ci   import { precompileWebview } from "./PrecompileWebview"
362e41f4b71Sopenharmony_ci   import { businessWebview } from "./BusinessWebview"
363e41f4b71Sopenharmony_ci   
364e41f4b71Sopenharmony_ci   @Entry
365e41f4b71Sopenharmony_ci   @Component
366e41f4b71Sopenharmony_ci   struct Index {
367e41f4b71Sopenharmony_ci     @State precompileNode: NodeController | undefined = undefined;
368e41f4b71Sopenharmony_ci     precompileController: webview.WebviewController = new webview.WebviewController();
369e41f4b71Sopenharmony_ci   
370e41f4b71Sopenharmony_ci     @State businessNode: NodeController | undefined = undefined;
371e41f4b71Sopenharmony_ci     businessController: webview.WebviewController = new webview.WebviewController();
372e41f4b71Sopenharmony_ci   
373e41f4b71Sopenharmony_ci     aboutToAppear(): void {
374e41f4b71Sopenharmony_ci       // Initialize the Web component used to inject local resources.
375e41f4b71Sopenharmony_ci       this.precompileNode = createNode(precompileWebview,
376e41f4b71Sopenharmony_ci         { url: "https://www.example.com/empty.html", controller: this.precompileController});
377e41f4b71Sopenharmony_ci     }
378e41f4b71Sopenharmony_ci
379e41f4b71Sopenharmony_ci     build() {
380e41f4b71Sopenharmony_ci       Column() {
381e41f4b71Sopenharmony_ci         // Load the service Web component at a proper time. In this example, the Web component is used in a button onclick event.
382e41f4b71Sopenharmony_ci         Button ("Loading page")
383e41f4b71Sopenharmony_ci           .onClick(() => {
384e41f4b71Sopenharmony_ci             this.businessNode = createNode(businessWebview, {
385e41f4b71Sopenharmony_ci               url:  "https://www.example.com/business.html",
386e41f4b71Sopenharmony_ci               controller: this.businessController
387e41f4b71Sopenharmony_ci             });
388e41f4b71Sopenharmony_ci           })
389e41f4b71Sopenharmony_ci         // The Web component used for the service.
390e41f4b71Sopenharmony_ci         NodeContainer(this.businessNode);
391e41f4b71Sopenharmony_ci       }
392e41f4b71Sopenharmony_ci     }
393e41f4b71Sopenharmony_ci   }
394e41f4b71Sopenharmony_ci   ```
395e41f4b71Sopenharmony_ci
396e41f4b71Sopenharmony_ciIf you want to update the local generated compiled bytecode, edit the value of **E-Tag** or **Last-Modified** in the **responseHeaders** parameter of **cacheOptions**, and call the API again.
397e41f4b71Sopenharmony_ci
398e41f4b71Sopenharmony_ci## Injecting Offline Resources Without Interception
399e41f4b71Sopenharmony_ciYou can use [injectOfflineResources()](../reference/apis-arkweb/js-apis-webview.md#injectofflineresources12) to inject images, style sheets, or script resources to the memory cache of applications before page loading.
400e41f4b71Sopenharmony_ci
401e41f4b71Sopenharmony_ciYou are advised to use this function together with dynamic components, use offline **Web** components to inject resources into the memory cache of the kernel, and load the service **Web** component at the appropriate time to use these resources. The example code is as follows:
402e41f4b71Sopenharmony_ci
403e41f4b71Sopenharmony_ci1. First, save **UIContext** to **localStorage** in **EntryAbility**.
404e41f4b71Sopenharmony_ci
405e41f4b71Sopenharmony_ci   ```ts
406e41f4b71Sopenharmony_ci   // EntryAbility.ets
407e41f4b71Sopenharmony_ci   import { UIAbility } from '@kit.AbilityKit';
408e41f4b71Sopenharmony_ci   import { window } from '@kit.ArkUI';
409e41f4b71Sopenharmony_ci
410e41f4b71Sopenharmony_ci   const localStorage: LocalStorage = new LocalStorage('uiContext');
411e41f4b71Sopenharmony_ci
412e41f4b71Sopenharmony_ci   export default class EntryAbility extends UIAbility {
413e41f4b71Sopenharmony_ci     storage: LocalStorage = localStorage;
414e41f4b71Sopenharmony_ci
415e41f4b71Sopenharmony_ci     onWindowStageCreate(windowStage: window.WindowStage) {
416e41f4b71Sopenharmony_ci       windowStage.loadContent('pages/Index', this.storage, (err, data) => {
417e41f4b71Sopenharmony_ci         if (err.code) {
418e41f4b71Sopenharmony_ci           return;
419e41f4b71Sopenharmony_ci         }
420e41f4b71Sopenharmony_ci
421e41f4b71Sopenharmony_ci         this.storage.setOrCreate<UIContext>("uiContext", windowStage.getMainWindowSync().getUIContext());
422e41f4b71Sopenharmony_ci       });
423e41f4b71Sopenharmony_ci     }
424e41f4b71Sopenharmony_ci   }
425e41f4b71Sopenharmony_ci   ```
426e41f4b71Sopenharmony_ci
427e41f4b71Sopenharmony_ci2. Compile the basic code of the dynamic component.
428e41f4b71Sopenharmony_ci
429e41f4b71Sopenharmony_ci   ```ts
430e41f4b71Sopenharmony_ci   // DynamicComponent.ets
431e41f4b71Sopenharmony_ci   import { NodeController, BuilderNode, FrameNode, UIContext } from '@kit.ArkUI';
432e41f4b71Sopenharmony_ci
433e41f4b71Sopenharmony_ci   export interface BuilderData {
434e41f4b71Sopenharmony_ci     url: string;
435e41f4b71Sopenharmony_ci     controller: WebviewController;
436e41f4b71Sopenharmony_ci   }
437e41f4b71Sopenharmony_ci
438e41f4b71Sopenharmony_ci   const storage = LocalStorage.getShared();
439e41f4b71Sopenharmony_ci
440e41f4b71Sopenharmony_ci   export class NodeControllerImpl extends NodeController {
441e41f4b71Sopenharmony_ci     private rootNode: BuilderNode<BuilderData[]> | null = null;
442e41f4b71Sopenharmony_ci     private wrappedBuilder: WrappedBuilder<BuilderData[]> | null = null;
443e41f4b71Sopenharmony_ci
444e41f4b71Sopenharmony_ci     constructor(wrappedBuilder: WrappedBuilder<BuilderData[]>) {
445e41f4b71Sopenharmony_ci       super();
446e41f4b71Sopenharmony_ci       this.wrappedBuilder = wrappedBuilder;
447e41f4b71Sopenharmony_ci     }
448e41f4b71Sopenharmony_ci
449e41f4b71Sopenharmony_ci     makeNode(): FrameNode | null {
450e41f4b71Sopenharmony_ci       if (this.rootNode != null) {
451e41f4b71Sopenharmony_ci         return this.rootNode.getFrameNode();
452e41f4b71Sopenharmony_ci       }
453e41f4b71Sopenharmony_ci       return null;
454e41f4b71Sopenharmony_ci     }
455e41f4b71Sopenharmony_ci
456e41f4b71Sopenharmony_ci     initWeb(url: string, controller: WebviewController) {
457e41f4b71Sopenharmony_ci       if(this.rootNode != null) {
458e41f4b71Sopenharmony_ci         return;
459e41f4b71Sopenharmony_ci       }
460e41f4b71Sopenharmony_ci
461e41f4b71Sopenharmony_ci       const uiContext: UIContext = storage.get<UIContext>("uiContext") as UIContext;
462e41f4b71Sopenharmony_ci       if (!uiContext) {
463e41f4b71Sopenharmony_ci         return;
464e41f4b71Sopenharmony_ci       }
465e41f4b71Sopenharmony_ci       this.rootNode = new BuilderNode(uiContext);
466e41f4b71Sopenharmony_ci       this.rootNode.build(this.wrappedBuilder, { url: url, controller: controller });
467e41f4b71Sopenharmony_ci     }
468e41f4b71Sopenharmony_ci   }
469e41f4b71Sopenharmony_ci
470e41f4b71Sopenharmony_ci   export const createNode = (wrappedBuilder: WrappedBuilder<BuilderData[]>, data: BuilderData) => {
471e41f4b71Sopenharmony_ci     const baseNode = new NodeControllerImpl(wrappedBuilder);
472e41f4b71Sopenharmony_ci     baseNode.initWeb(data.url, data.controller);
473e41f4b71Sopenharmony_ci     return baseNode;
474e41f4b71Sopenharmony_ci   }
475e41f4b71Sopenharmony_ci   ```
476e41f4b71Sopenharmony_ci
477e41f4b71Sopenharmony_ci3. Compile the component code for injecting resources. In this example, the local resource reads the local file in the **rawfile** directory through **readRawFile()**.
478e41f4b71Sopenharmony_ci
479e41f4b71Sopenharmony_ci   <!--code_no_check-->
480e41f4b71Sopenharmony_ci   ```ts
481e41f4b71Sopenharmony_ci   // InjectWebview.ets
482e41f4b71Sopenharmony_ci   import { webview } from '@kit.ArkWeb';
483e41f4b71Sopenharmony_ci   import { resourceConfigs } from "./Resource";
484e41f4b71Sopenharmony_ci   import { BuilderData } from "./DynamicComponent";
485e41f4b71Sopenharmony_ci
486e41f4b71Sopenharmony_ci   @Builder
487e41f4b71Sopenharmony_ci   function WebBuilder(data: BuilderData) {
488e41f4b71Sopenharmony_ci     Web({ src: data.url, controller: data.controller })
489e41f4b71Sopenharmony_ci       .onControllerAttached(async () => {
490e41f4b71Sopenharmony_ci         try {
491e41f4b71Sopenharmony_ci           data.controller.injectOfflineResources(await getData ());
492e41f4b71Sopenharmony_ci         } catch (err) {
493e41f4b71Sopenharmony_ci           console.error("error: " + err.code + " " + err.message);
494e41f4b71Sopenharmony_ci         }
495e41f4b71Sopenharmony_ci       })
496e41f4b71Sopenharmony_ci       .fileAccess(true)
497e41f4b71Sopenharmony_ci   }
498e41f4b71Sopenharmony_ci
499e41f4b71Sopenharmony_ci   export const injectWebview = wrapBuilder<BuilderData[]>(WebBuilder);
500e41f4b71Sopenharmony_ci
501e41f4b71Sopenharmony_ci   export async function getData() {
502e41f4b71Sopenharmony_ci     const resourceMapArr: Array<webview.OfflineResourceMap> = [];
503e41f4b71Sopenharmony_ci
504e41f4b71Sopenharmony_ci     // Read the configuration, and read the file content from the rawfile directory.
505e41f4b71Sopenharmony_ci     for (let config of resourceConfigs) {
506e41f4b71Sopenharmony_ci       let buf: Uint8Array = new Uint8Array(0);
507e41f4b71Sopenharmony_ci       if (config.localPath) {
508e41f4b71Sopenharmony_ci         buf = await readRawFile(config.localPath);
509e41f4b71Sopenharmony_ci       }
510e41f4b71Sopenharmony_ci
511e41f4b71Sopenharmony_ci       resourceMapArr.push({
512e41f4b71Sopenharmony_ci         urlList: config.urlList,
513e41f4b71Sopenharmony_ci         resource: buf,
514e41f4b71Sopenharmony_ci         responseHeaders: config.responseHeaders,
515e41f4b71Sopenharmony_ci         type: config.type,
516e41f4b71Sopenharmony_ci       })
517e41f4b71Sopenharmony_ci     }
518e41f4b71Sopenharmony_ci
519e41f4b71Sopenharmony_ci     return resourceMapArr;
520e41f4b71Sopenharmony_ci   }
521e41f4b71Sopenharmony_ci
522e41f4b71Sopenharmony_ci   export async function readRawFile(url: string) {
523e41f4b71Sopenharmony_ci     try {
524e41f4b71Sopenharmony_ci       return await getContext().resourceManager.getRawFileContent(url);
525e41f4b71Sopenharmony_ci     } catch (err) {
526e41f4b71Sopenharmony_ci       return new Uint8Array(0);
527e41f4b71Sopenharmony_ci     }
528e41f4b71Sopenharmony_ci   }
529e41f4b71Sopenharmony_ci   ```
530e41f4b71Sopenharmony_ci
531e41f4b71Sopenharmony_ci4. Compile the code of the service component.
532e41f4b71Sopenharmony_ci
533e41f4b71Sopenharmony_ci   <!--code_no_check-->
534e41f4b71Sopenharmony_ci   ```ts
535e41f4b71Sopenharmony_ci   // BusinessWebview.ets
536e41f4b71Sopenharmony_ci   import { BuilderData } from "./DynamicComponent";
537e41f4b71Sopenharmony_ci
538e41f4b71Sopenharmony_ci   @Builder
539e41f4b71Sopenharmony_ci   function WebBuilder(data: BuilderData) {
540e41f4b71Sopenharmony_ci     // The component can be extended as required.
541e41f4b71Sopenharmony_ci     Web({ src: data.url, controller: data.controller })
542e41f4b71Sopenharmony_ci       .cacheMode(CacheMode.Default)
543e41f4b71Sopenharmony_ci   }
544e41f4b71Sopenharmony_ci
545e41f4b71Sopenharmony_ci   export const businessWebview = wrapBuilder<BuilderData[]>(WebBuilder);
546e41f4b71Sopenharmony_ci   ```
547e41f4b71Sopenharmony_ci
548e41f4b71Sopenharmony_ci5. Edit the resource configuration information.
549e41f4b71Sopenharmony_ci
550e41f4b71Sopenharmony_ci   ```ts
551e41f4b71Sopenharmony_ci   // Resource.ets
552e41f4b71Sopenharmony_ci   import { webview } from '@kit.ArkWeb';
553e41f4b71Sopenharmony_ci
554e41f4b71Sopenharmony_ci   export interface ResourceConfig {
555e41f4b71Sopenharmony_ci     urlList: Array<string>,
556e41f4b71Sopenharmony_ci     type: webview.OfflineResourceType,
557e41f4b71Sopenharmony_ci     responseHeaders: Array<Header>,
558e41f4b71Sopenharmony_ci     localPath: string, // The path for storing local resources in the rawfile directory.
559e41f4b71Sopenharmony_ci   }
560e41f4b71Sopenharmony_ci
561e41f4b71Sopenharmony_ci   export const resourceConfigs: Array<ResourceConfig> = [
562e41f4b71Sopenharmony_ci     {
563e41f4b71Sopenharmony_ci       localPath: "example.png",
564e41f4b71Sopenharmony_ci       urlList: [
565e41f4b71Sopenharmony_ci         "https://www.example.com/",
566e41f4b71Sopenharmony_ci         "https://www.example.com/path1/example.png",
567e41f4b71Sopenharmony_ci         "https://www.example.com/path2/example.png",
568e41f4b71Sopenharmony_ci       ],
569e41f4b71Sopenharmony_ci       type: webview.OfflineResourceType.IMAGE,
570e41f4b71Sopenharmony_ci       responseHeaders: [
571e41f4b71Sopenharmony_ci         { headerKey: "Cache-Control", headerValue: "max-age=1000" },
572e41f4b71Sopenharmony_ci         { headerKey: "Content-Type", headerValue: "image/png" },
573e41f4b71Sopenharmony_ci       ]
574e41f4b71Sopenharmony_ci     },
575e41f4b71Sopenharmony_ci     {
576e41f4b71Sopenharmony_ci       localPath: "example.js",
577e41f4b71Sopenharmony_ci       urlList: [ // Only one URL is provided. This URL is used as both the resource origin and the network request address of the resource.
578e41f4b71Sopenharmony_ci         "https://www.example.com/example.js",
579e41f4b71Sopenharmony_ci       ],
580e41f4b71Sopenharmony_ci       type: webview.OfflineResourceType.CLASSIC_JS,
581e41f4b71Sopenharmony_ci       responseHeaders: [
582e41f4b71Sopenharmony_ci         // Used in <script crossorigin="anoymous" /> mode to provide additional response headers.
583e41f4b71Sopenharmony_ci         { headerKey: "Cross-Origin", headerValue:"anonymous" }
584e41f4b71Sopenharmony_ci       ]
585e41f4b71Sopenharmony_ci     },
586e41f4b71Sopenharmony_ci   ];
587e41f4b71Sopenharmony_ci   ```
588e41f4b71Sopenharmony_ci
589e41f4b71Sopenharmony_ci6. Use the components on the page.
590e41f4b71Sopenharmony_ci   ```ts
591e41f4b71Sopenharmony_ci   // Index.ets
592e41f4b71Sopenharmony_ci   import { webview } from '@kit.ArkWeb';
593e41f4b71Sopenharmony_ci   import { NodeController } from '@kit.ArkUI';
594e41f4b71Sopenharmony_ci   import { createNode } from "./DynamicComponent"
595e41f4b71Sopenharmony_ci   import { injectWebview } from "./InjectWebview"
596e41f4b71Sopenharmony_ci   import { businessWebview } from "./BusinessWebview"
597e41f4b71Sopenharmony_ci
598e41f4b71Sopenharmony_ci   @Entry
599e41f4b71Sopenharmony_ci   @Component
600e41f4b71Sopenharmony_ci   struct Index {
601e41f4b71Sopenharmony_ci     @State injectNode: NodeController | undefined = undefined;
602e41f4b71Sopenharmony_ci     injectController: webview.WebviewController = new webview.WebviewController();
603e41f4b71Sopenharmony_ci
604e41f4b71Sopenharmony_ci     @State businessNode: NodeController | undefined = undefined;
605e41f4b71Sopenharmony_ci     businessController: webview.WebviewController = new webview.WebviewController();
606e41f4b71Sopenharmony_ci
607e41f4b71Sopenharmony_ci     aboutToAppear(): void {
608e41f4b71Sopenharmony_ci       // Initialize the Web component used to inject local resources and provide an empty HTML page as the URL.
609e41f4b71Sopenharmony_ci       this.injectNode = createNode(injectWebview,
610e41f4b71Sopenharmony_ci           { url: "https://www.example.com/empty.html", controller: this.injectController});
611e41f4b71Sopenharmony_ci     }
612e41f4b71Sopenharmony_ci
613e41f4b71Sopenharmony_ci     build() {
614e41f4b71Sopenharmony_ci       Column() {
615e41f4b71Sopenharmony_ci         // Load the service Web component at a proper time. In this example, the Web component is used in a button onclick event.
616e41f4b71Sopenharmony_ci         Button ("Loading page")
617e41f4b71Sopenharmony_ci           .onClick(() => {
618e41f4b71Sopenharmony_ci             this.businessNode = createNode(businessWebview, {
619e41f4b71Sopenharmony_ci               url: "https://www.example.com/business.html",
620e41f4b71Sopenharmony_ci               controller: this.businessController
621e41f4b71Sopenharmony_ci             });
622e41f4b71Sopenharmony_ci           })
623e41f4b71Sopenharmony_ci         // The Web component used for the service.
624e41f4b71Sopenharmony_ci         NodeContainer(this.businessNode);
625e41f4b71Sopenharmony_ci       }
626e41f4b71Sopenharmony_ci     }
627e41f4b71Sopenharmony_ci   }
628e41f4b71Sopenharmony_ci   ```
629e41f4b71Sopenharmony_ci
630e41f4b71Sopenharmony_ci7. The example of a loaded HTML web page is as follows.
631e41f4b71Sopenharmony_ci
632e41f4b71Sopenharmony_ci   ```HTML
633e41f4b71Sopenharmony_ci   <!DOCTYPE html>
634e41f4b71Sopenharmony_ci   <html lang="en">
635e41f4b71Sopenharmony_ci   <head></head>
636e41f4b71Sopenharmony_ci   <body>
637e41f4b71Sopenharmony_ci     <img src="https://www.example.com/path1/request.png" />
638e41f4b71Sopenharmony_ci     <img src="https://www.example.com/path2/request.png" />
639e41f4b71Sopenharmony_ci     <script src="https://www.example.com/example.js" crossorigin="anonymous"></script>
640e41f4b71Sopenharmony_ci   </body>
641e41f4b71Sopenharmony_ci   </html>
642e41f4b71Sopenharmony_ci   ```
643