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