feat: catch frames errors (#47)

diff --git a/README.md b/README.md
index bbbaf8d..849ac9e 100644
--- a/README.md
+++ b/README.md
@@ -87,7 +87,7 @@
 2. Manual reporting  
 This method can be used in all single page application scenarios. This method can be used if the first method is invalid.    
 The SDK provides a set page method to manually update the page name when data is reported. When this method is called, the page PV will be re reported by default. For details, see setPerformance().  
-```
+```js
 app.on('routeChange', function (next) {
   ClientMonitor.setPerformance({
     collector: 'http://127.0.0.1:8080',
@@ -103,6 +103,78 @@
 
 Support tracking these([XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) and [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)) two modes of data requests. At the same time, Support tracking libraries and tools that base on XMLHttpRequest and fetch, such as [Axios](https://github.com/axios/axios), [SuperAgent](https://github.com/visionmedia/superagent), [OpenApi](https://www.openapis.org/) and so on.
 
+## Catching errors in frames, including React, Angular, Vue.
+
+```js
+// Angular
+import { ErrorHandler } from '@angular/core';
+import ClientMonitor from 'skywalking-client-js';
+export class AppGlobalErrorhandler implements ErrorHandler {
+  handleError(error) {
+    ClientMonitor.reportFrameErrors({
+      collector: 'http://127.0.0.1',
+      service: 'angular-demo',
+      pagePath: '/app',
+      serviceVersion: 'v1.0.0',
+    }, error);
+  }
+}
+@NgModule({
+  ...
+  providers: [{provide: ErrorHandler, useClass: AppGlobalErrorhandler}]
+})
+class AppModule {}
+```
+
+```js
+// React
+class ErrorBoundary extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = { hasError: false };
+  }
+
+  static getDerivedStateFromError(error) {
+    // Update state so the next render will show the fallback UI.
+    return { hasError: true };
+  }
+
+  componentDidCatch(error, errorInfo) {
+    // You can also log the error to an error reporting service
+    ClientMonitor.reportFrameErrors({
+      collector: 'http://127.0.0.1',
+      service: 'react-demo',
+      pagePath: '/app',
+      serviceVersion: 'v1.0.0',
+    }, error);
+  }
+
+  render() {
+    if (this.state.hasError) {
+      // You can render any custom fallback UI
+      return <h1>Something went wrong.</h1>;
+    }
+
+    return this.props.children; 
+  }
+}
+<ErrorBoundary>
+  <MyWidget />
+</ErrorBoundary>
+```
+
+```js
+// Vue
+Vue.config.errorHandler = (error) => {
+  ClientMonitor.reportFrameErrors({
+    collector: 'http://127.0.0.1',
+    service: 'vue-demo',
+    pagePath: '/app',
+    serviceVersion: 'v1.0.0',
+  }, error);
+}
+```
+
 # Demo project
 
 Demo project provides instrumented web application with necessary environment, you could just simple use it to see the data SkyWalking collected and how SkyWalking visualizes on the UI. 
diff --git a/package-lock.json b/package-lock.json
index 065ca61..d02c275 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "skywalking-client-js",
-  "version": "0.3.0",
+  "version": "0.5.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/src/errors/frames.ts b/src/errors/frames.ts
new file mode 100644
index 0000000..7471a8d
--- /dev/null
+++ b/src/errors/frames.ts
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import uuid from '../services/uuid';
+import Base from '../services/base';
+import { GradeTypeEnum, ErrorsCategory } from '../services/constant';
+
+class FrameErrors extends Base {
+  public handleErrors(
+    options: { service: string; serviceVersion: string; pagePath: string; collector?: string },
+    error: Error,
+  ) {
+    this.logInfo = {
+      uniqueId: uuid(),
+      service: options.service,
+      serviceVersion: options.serviceVersion,
+      pagePath: options.pagePath,
+      category: ErrorsCategory.JS_ERROR,
+      grade: GradeTypeEnum.ERROR,
+      errorUrl: error.name || location.href,
+      message: error.message,
+      collector: options.collector || location.origin,
+      stack: error.stack,
+    };
+    this.traceInfo();
+  }
+}
+export default new FrameErrors();
diff --git a/src/errors/index.ts b/src/errors/index.ts
index 180a7ba..4fd6eec 100644
--- a/src/errors/index.ts
+++ b/src/errors/index.ts
@@ -20,7 +20,6 @@
 import AjaxErrors from './ajax';
 import ResourceErrors from './resource';
 import VueErrors from './vue';
+import FrameErrors from './frames';
 
-export {
-  JSErrors, PromiseErrors, AjaxErrors, ResourceErrors, VueErrors,
-};
+export { JSErrors, PromiseErrors, AjaxErrors, ResourceErrors, VueErrors, FrameErrors };
diff --git a/src/monitor.ts b/src/monitor.ts
index 8844305..c2cea24 100644
--- a/src/monitor.ts
+++ b/src/monitor.ts
@@ -15,8 +15,8 @@
  * limitations under the License.
  */
 
-import { CustomOptionsType } from './types';
-import { JSErrors, PromiseErrors, AjaxErrors, ResourceErrors, VueErrors } from './errors/index';
+import { CustomOptionsType, CustomReportOptions } from './types';
+import { JSErrors, PromiseErrors, AjaxErrors, ResourceErrors, VueErrors, FrameErrors } from './errors/index';
 import tracePerf from './performance/index';
 import traceSegment from './trace/segment';
 
@@ -39,7 +39,7 @@
       ...this.customOptions,
       ...configs,
     };
-    this.errors(this.customOptions);
+    this.catchErrors(this.customOptions);
     if (!this.customOptions.enableSPA) {
       this.performance(this.customOptions);
     }
@@ -70,7 +70,7 @@
       );
     }
   },
-  errors(options: CustomOptionsType) {
+  catchErrors(options: CustomOptionsType) {
     const { service, pagePath, serviceVersion, collector } = options;
 
     if (options.jsErrors) {
@@ -95,6 +95,9 @@
     };
     this.performance(this.customOptions);
   },
+  reportFrameErrors(configs: CustomReportOptions, error: Error) {
+    FrameErrors.handleErrors(configs, error);
+  },
 };
 
 export default ClientMonitor;
diff --git a/src/performance/index.ts b/src/performance/index.ts
index 9c5d8ef..4cb068c 100644
--- a/src/performance/index.ts
+++ b/src/performance/index.ts
@@ -51,7 +51,7 @@
       new Report('PERF', options.collector).sendByXhr(perfInfo);
       // clear perf data
       this.clearPerf();
-    }, 30000);
+    }, 6000);
   }
 
   private clearPerf() {
diff --git a/src/types.d.ts b/src/types.d.ts
index f98546b..b22714e 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -15,11 +15,7 @@
  * limitations under the License.
  */
 
-export interface CustomOptionsType {
-  collector?: string;
-  service: string;
-  pagePath: string;
-  serviceVersion: string;
+export interface CustomOptionsType extends CustomReportOptions {
   jsErrors?: boolean;
   apiErrors?: boolean;
   resourceErrors?: boolean;
@@ -31,3 +27,10 @@
   detailMode?: boolean;
   noTraceOrigins?: (string | RegExp)[];
 }
+
+export interface CustomReportOptions {
+  collector?: string;
+  service: string;
+  pagePath: string;
+  serviceVersion: string;
+}