preface

The previous article covered how to catch production environment errors and how to undo them.

This time I will show you how to render the captured bug to the page.

Souce-map-js + Vue restore generated environment error, make JS error no hiding

starts

To install first element – the UI

Modify the main js

... Vue.config.errorHandler =async (err, vm) => {
  const jsError = {
    stack_frames: ErrorStackParser.parse(err),
    message: err.message,
    stack: err.stack,
    error_name: err.name
  }
  vm.$message.error('You triggered one${err.name}Error `);
  localStorage.setItem("jsErrorList".JSONStringify (jsError)]}...Copy the code

Considering that some friends may not end, simply will report errors stored locally. (Actually lazy… Don’t want to write…

Create a new Trigger. Vue in the Views directory

<template>
  <div class="about">
    <p @click="triggerTypeError()">Trigger TypeError</p>
    <el-divider></el-divider>
    <p @click="triggerReferenceError()">Trigger a ReferenceError</p>
    <el-divider></el-divider>
    <p @click="triggerSyntaxError()">Trigger a SyntaxError</p>
  </div>
</template>
<script>
export default {
  name: "ErrorTrigger".methods: {
    triggerTypeError() {
        if (this.typeError.length > 0) {
            console.log("err!"); }},triggerReferenceError() {
        throw new ReferenceError('Hello'.'someFile.js'.10);
    },
    triggerSyntaxError () {
        throw new SyntaxError('Hello'.'someFile.js'.10); }}}</script>
Copy the code

It is used to trigger js errors, which will be intercepted by main.js and stored locally.

App.vue one for viewing and one for triggering JS errors.

  <div id="app">
    <el-row>
      <el-button @click="routerPush('/')">Viewing THE Js Exception</el-button>
      <el-button type="primary"  @click="routerPush('/trigger')">Trigger Js exception</el-button>
    </el-row>
    <el-divider></el-divider>
    <router-view/>
  </div>
Copy the code

Then modify home.vue


  <div v-if="js_error">
      <pre>
        {{js_error.stack}}
      </pre>
      <el-collapse v-model="activeName" accordion>
        <el-collapse-item v-for="(item, index) in js_error.stack_frames" :key="index" :title="substrSourceTitle(item.source)" :name="index">
          <el-row :gutter="20">
            <el-col :span="20">
                <div >{{item.fileName}}</div>
            </el-col>
            <el-col :span="4">
              <el-button size="small" type="primary" @click="oepnDialog(item, index)">Mapping source</el-button>
            </el-col>
          </el-row>
        </el-collapse-item>
      </el-collapse>< / div >...created() {
  try {
    const js_error = localStorage.getItem("jsErrorList");
    if (js_error) {
      this.js_error = JSON.parse(js_error)
      console.log(this.js_error); }}catch(err) {
    console.log(err); }},methods: {
    substrSourceTitle(str) {   // Trim the title... It's too long. Don't worry, it won't be that long in a production environment...
        return  str.substr(0.100) + '... '}}...Copy the code

Look at the effect… Not bad.

Reduction of error

This is actually similar to the last article, I have made some adjustments here.

Home.vue

. <el-dialog title="SourceMap mapping"
      :visible.sync="visible"
      width="500px"
      :before-close="handleClose">
      <el-tabs v-model="activeTabName">
        <el-tab-pane label="Local upload" name="local">
          <el-upload
            style="width: 100%"
            class="upload-demo"
            drag
            action=""
            :before-upload="sourceMapUpload">
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">Drag the file here, or<em>Click on the upload</em></div>
          </el-upload>
        </el-tab-pane>
        <el-tab-pane label="Remote loading" name="request">The remote loading</el-tab-pane>
    </el-tabs>
  </el-dialog>
...
    methods: {
      oepnDialog(stackFrame, index) {
        this.stackFrame = {
          line: stackFrame.lineNumber,
          cloum: stackFrame.columnNumber,
          index: index,
        };
        this.visible = true;
      },
      substrSourceTitle(str) {
        return  str.substr(0.100) + '... '
      },
      handleClose(done) {
        done();
      },
      sourceMapUpload(file) {
        if (file.name.substring(file.name.lastIndexOf('. ') + 1)! = ='map') {
          this.$message.error('Please upload the.js.map file! `);
          return
        }
        const reader = new FileReader()
        reader.readAsText(file, 'UTF-8')
        reader.onload = event= > {
          const look_source = this.lookSource(event.target.result, this.stackFrame.line, this.stackFrame.cloum)
          this.js_error.stack_frames[this.stackFrame.index].origin = look_source

          this.visible = false;
        }
        return false
      },
      lookSource(source_map, line, column)  {
        try {
          const consumer = new sourceMap.SourceMapConsumer(source_map)
          const lookUpRes = consumer.originalPositionFor({
            line: line,
            column: column
          })
          const source = consumer.sourceContentFor(lookUpRes.source)
          return {
            source,
            column: lookUpRes.column,
            line: lookUpRes.line
          }
        } catch(e) {
          this.$message.error('Failed to resolve sourceMap! `);
          console.log(e);
          return null}}}Copy the code

This will pop up a Dialog to upload the.js.map file, which we parse to get the source code.

Render error message

The source code is resolved, so how to render the error message?

Create the component precode.vue

<template> <div class="pre_code"> <div class="errdetail"> <pre class="errCode" v-html="preLineStartEnd()"></pre> </div> </div> </template> <script> export default { name: 'PreCode', props: { orgin: Object, }, methods: {preLineStartEnd() {const transformationLine = this.component.split ('\n') const len = transformationLine.length - 1 const start = this.orgin.line - 3 >= 0 ? this.orgin.line - 3 : 0 const end = start + 5 >= len: start + 5 const line = this.org.line let newLines = []; for(var i = start; i <= end; i++) { const content = i + 1 + '. ' + this.encodeHTML(transformationLine[i]) newLines.push(`<div class='code-line ${i + 1 == line ? 'heightlight' : ''}'>${content}</div>`); } return newLines.join("") }, encodeHTML(str) { if (! str || str.length == 0) return '' return str.replace(/&/g, '&#38; ').replace(/</g, '&lt; ').replace(/>/g, '&gt; ').replace(/'/g, '&#39; ') } } } </script> <style> .errCode { padding: 10px; overflow: hidden; font-family: consolas,monospace; word-wrap: normal; } .code-line { padding: 4px; } .heightlight { color: #fff; background-color: #6c5fc7; } </style>Copy the code

Use components in home.vue

. <el-col :span="20">
  <template v-if="item.origin">
    <PreCode v-if="item.origin" :orgin="item.origin"></PreCode>
  </template>
  <template v-if=! "" item.origin">
    <div >{{item.fileName}}</div>
  </template>
</el-col>
...
import PreCode from ".. /components/PreCode".components: {
  PreCode
}, 
Copy the code

Parse succeeded!

The end

I spent about two months of my spare time writing a monitoring system from the front end to the back end, from which I gained a lot.

Because the report is very much, the report data with ORM also do not know how to check, simply I use SQL to write all, is also to strengthen the SQL this weakness.

Go is much better understood, there are no generics and the error mechanism is disgusting… But fortunately easy to understand, very easy to use. I recommend you to try it.

I am most satisfied with the monitoring system source-map-js parsing exception and user behavior path, probably because ICONS are more beautiful…