Repository: ice-lab/icestark
Pull request #577 (2022-04-21 06:36:55)

Feat/sandbox inject custom proxy
#576 
增加 sandbox 注入对象的能力。通过注入对象，可以接管对 window 上特定变量的访问/修改

maoxiaoke: @HuColin 可否顺便处理下 icestark 和 icestark-module 的逻辑，使用户可以通过 

```js
<AppRoute
  sandbox={{ injection: {} }}
/>
```

的方式使用
HuColin: > @HuColin 可否顺便处理下 icestark 和 icestark-module 的逻辑，使用户可以通过
> 
> ```js
> <AppRoute
>   sandbox={{ injection: {} }}
> />
> ```
>   
> 的方式使用
> ```

`icestark` 和 `icestark-module` 不需要而外处理也能用吧
icestark 创建 sandbox 的地方
https://github.com/ice-lab/icestark/blob/1afc4101fcf2bfb163f2307106f8dcc6900e3ff6/packages/icestark/src/util/handleAssets.ts#L764-L777
icestark-module 创建 sandbox 的地方
https://github.com/ice-lab/icestark/blob/1afc4101fcf2bfb163f2307106f8dcc6900e3ff6/packages/icestark-module/src/modules.tsx#L101-L118
这两个地方都默认会将 sandbox 属性用于创建 sandbox 实例

maoxiaoke: > > @HuColin 可否顺便处理下 icestark 和 icestark-module 的逻辑，使用户可以通过
> > ```js
> > <AppRoute
> >   sandbox={{ injection: {} }}
> > />
> > ```
> > 
> > 
> >     
> >       
> >     
> > 
> >       
> >     
> > 
> >     
> >   
> > 的方式使用
> 
> `icestark` 和 `icestark-module` 不需要而外处理也能用吧 icestark 创建 sandbox 的地方
> 
> https://github.com/ice-lab/icestark/blob/1afc4101fcf2bfb163f2307106f8dcc6900e3ff6/packages/icestark/src/util/handleAssets.ts#L764-L777
> 
> 
> icestark-module 创建 sandbox 的地方
> https://github.com/ice-lab/icestark/blob/1afc4101fcf2bfb163f2307106f8dcc6900e3ff6/packages/icestark-module/src/modules.tsx#L101-L118
> 
> 
> 这两个地方都默认会将 sandbox 属性用于创建 sandbox 实例

希望是能支持用户传入 injection，这样就不需要单独引入 sandbox 了

Patch:
diff --git a/packages/sandbox/src/index.ts b/packages/sandbox/src/index.ts
index b91cf98..26c7cc5 100644
--- a/packages/sandbox/src/index.ts
+++ b/packages/sandbox/src/index.ts
@@ -1,5 +1,6 @@
 export interface SandboxProps {
   multiMode?: boolean;
+  injection?: Record<PropertyKey, any>;
 }
 
 export interface SandboxConstructor {
@@ -33,6 +34,8 @@ export default class Sandbox {
 
   private multiMode = false;
 
+  private injection: Record<PropertyKey, any> = {};
+
   private eventListeners = {};
 
   private timeoutIds: number[] = [];
@@ -46,7 +49,7 @@ export default class Sandbox {
   public sandboxDisabled: boolean;
 
   constructor(props: SandboxProps = {}) {
-    const { multiMode } = props;
+    const { multiMode, injection } = props;
     if (!window.Proxy) {
       console.warn('proxy sandbox is not support by current browser');
       this.sandboxDisabled = true;
@@ -54,6 +57,7 @@ export default class Sandbox {
     // enable multiMode in case of create mulit sandbox in same time
     this.multiMode = multiMode;
     this.sandbox = null;
+    this.injection = injection;
   }
 
   createProxySandbox(injection?: object) {
@@ -65,6 +69,9 @@ export default class Sandbox {
     const originalSetInterval = window.setInterval;
     const originalSetTimeout = window.setTimeout;
 
+    // quote `this` to be used in Proxy method
+    const _self = this;
+
     // hijack addEventListener
     proxyWindow.addEventListener = (eventName, fn, ...rest) => {
       this.eventListeners[eventName] = (this.eventListeners[eventName] || []);
@@ -135,7 +142,10 @@ export default class Sandbox {
         }
 
         // search from injection
-        const injectionValue = injection && injection[p];
+        const injectionValue = ({
+          ...(_self.injection),
+          ...injection,
+        })[p];
         if (injectionValue) {
           return injectionValue;
         }


Test patch:
diff --git a/packages/sandbox/__tests__/index.spec.ts b/packages/sandbox/__tests__/index.spec.ts
index fea1ee9..06d6c6a 100644
--- a/packages/sandbox/__tests__/index.spec.ts
+++ b/packages/sandbox/__tests__/index.spec.ts
@@ -151,3 +151,31 @@ describe('callable functions in sandbox', () => {
     expect(error).toBe(null);
   });
 });
+
+describe('inject value to sandbox', () => {
+  const testObject = { a: 1 };
+  const testProxy = new Proxy(testObject, {
+    get(target, p, receiver) {
+        if(p === 'a') {
+          return 2;
+        }
+        return Reflect.get(target, p);
+    }
+  })
+  // in order to pass value outof sandbox to validate, set multiMode false 
+  const sandbox = new Sandbox({multiMode: false, injection: {testObject: testProxy}});
+  test('inject proxy object in sandbox', () => {
+    // @ts-ignore
+    window.testObject = testObject;
+    // @ts-ignore
+    window.result = undefined;
+    sandbox.execScriptInSandbox(
+      `
+        window.result = window.testObject.a;
+      `,
+    );
+
+    // @ts-ignore
+    expect(window.result).toBe(2);
+  })
+})