log.ts 3.7 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
import fs from 'fs'
fxy060608's avatar
fxy060608 已提交
2
import path from 'path'
fxy060608's avatar
fxy060608 已提交
3
import colors from 'picocolors'
fxy060608's avatar
fxy060608 已提交
4 5 6
import type { RollupError } from 'rollup'
import type { LogErrorOptions } from 'vite'
import { NodeTypes } from '@vue/compiler-core'
fxy060608's avatar
fxy060608 已提交
7
import { normalizePath } from '../utils'
fxy060608's avatar
fxy060608 已提交
8
import { Formatter } from '../logs/format'
fxy060608's avatar
fxy060608 已提交
9 10 11 12

import { EXTNAME_VUE_RE } from '../constants'
import { parseVue } from '../vite/utils/ast'
import { generateCodeFrame } from '../vite/plugins/vitejs/utils'
fxy060608's avatar
fxy060608 已提交
13

fxy060608's avatar
fxy060608 已提交
14
const SIGNAL_H5_LOCAL = ' > Local:'
fxy060608's avatar
fxy060608 已提交
15
const SIGNAL_H5_NETWORK = ' > Network:'
fxy060608's avatar
fxy060608 已提交
16

fxy060608's avatar
fxy060608 已提交
17
const networkLogs: string[] = []
fxy060608's avatar
fxy060608 已提交
18

fxy060608's avatar
fxy060608 已提交
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
export function formatAtFilename(
  filename: string,
  line?: number,
  column?: number
) {
  return `at ${colors.cyan(
    normalizePath(
      path.relative(process.env.UNI_INPUT_DIR, filename.split('?')[0])
    ) +
      ':' +
      (line || 1) +
      ':' +
      (column || 0)
  )}`
}

fxy060608's avatar
fxy060608 已提交
35 36
export const h5ServeFormatter: Formatter = {
  test(msg) {
fxy060608's avatar
fxy060608 已提交
37
    return msg.includes(SIGNAL_H5_LOCAL) || msg.includes(SIGNAL_H5_NETWORK)
fxy060608's avatar
fxy060608 已提交
38 39
  },
  format(msg) {
fxy060608's avatar
fxy060608 已提交
40 41 42
    if (msg.includes(SIGNAL_H5_NETWORK)) {
      networkLogs.push(msg)
      process.nextTick(() => {
fxy060608's avatar
fxy060608 已提交
43 44 45 46 47 48 49
        if (networkLogs.length) {
          // 延迟打印所有 network,仅最后一个 network 替换 > 为 -,通知 hbx
          const len = networkLogs.length - 1
          networkLogs[len] = networkLogs[len].replace('>', '-')
          console.log(networkLogs.join('\n'))
          networkLogs.length = 0
        }
fxy060608's avatar
fxy060608 已提交
50 51 52
      })
      return ''
    }
fxy060608's avatar
fxy060608 已提交
53 54 55 56 57 58 59
    return msg.replace('>', '-')
  },
}

const REMOVED_MSGS = [
  'build started...',
  (msg: string) => {
fxy060608's avatar
fxy060608 已提交
60
    return /built in [0-9]+ms\./.test(msg)
fxy060608's avatar
fxy060608 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73
  },
  'watching for file changes...',
]
export const removeInfoFormatter: Formatter = {
  test(msg) {
    return !!REMOVED_MSGS.find((m) =>
      typeof m === 'string' ? msg.includes(m) : m(msg)
    )
  },
  format() {
    return ''
  },
}
fxy060608's avatar
fxy060608 已提交
74
const REMOVED_WARN_MSGS: string[] = []
75 76 77 78 79 80 81 82
export const removeWarnFormatter: Formatter = {
  test(msg) {
    return !!REMOVED_WARN_MSGS.find((m) => msg.includes(m))
  },
  format() {
    return ''
  },
}
fxy060608's avatar
fxy060608 已提交
83

fxy060608's avatar
fxy060608 已提交
84 85 86
export const errorFormatter: Formatter<LogErrorOptions> = {
  test(_, opts) {
    return !!(opts && opts.error)
fxy060608's avatar
fxy060608 已提交
87
  },
fxy060608's avatar
fxy060608 已提交
88 89
  format(_, opts) {
    return buildErrorMessage(opts!.error!, [], false)
fxy060608's avatar
fxy060608 已提交
90 91 92
  },
}

fxy060608's avatar
fxy060608 已提交
93 94 95 96 97 98 99
function buildErrorMessage(
  err: RollupError,
  args: string[] = [],
  includeStack = true
): string {
  if (err.plugin) {
    args.push(
fxy060608's avatar
fxy060608 已提交
100
      `${colors.magenta('[plugin:' + err.plugin + ']')} ${colors.red(
fxy060608's avatar
fxy060608 已提交
101 102 103
        err.message
      )}`
    )
fxy060608's avatar
fxy060608 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    if (
      err.loc &&
      err.hook === 'transform' &&
      err.plugin === 'rollup-plugin-dynamic-import-variables' &&
      err.id &&
      EXTNAME_VUE_RE.test(err.id)
    ) {
      try {
        const ast = parseVue(fs.readFileSync(err.id, 'utf8'), [])
        const scriptNode = ast.children.find(
          (node) => node.type === NodeTypes.ELEMENT && node.tag === 'script'
        )
        if (scriptNode) {
          const scriptLoc = scriptNode.loc
          args.push(
            colors.yellow(pad(generateCodeFrame(scriptLoc.source, err.loc)))
          )
fxy060608's avatar
fxy060608 已提交
121
          // correct error location
fxy060608's avatar
fxy060608 已提交
122 123 124 125
          err.loc.line = scriptLoc.start.line + err.loc.line - 1
        }
      } catch (e: any) {}
    }
fxy060608's avatar
fxy060608 已提交
126
  } else {
fxy060608's avatar
fxy060608 已提交
127
    args.push(colors.red(err.message))
fxy060608's avatar
fxy060608 已提交
128 129
  }
  if (err.id) {
fxy060608's avatar
fxy060608 已提交
130
    args.push(formatAtFilename(err.id, err.loc?.line, err.loc?.column))
fxy060608's avatar
fxy060608 已提交
131 132
  }
  if (err.frame) {
fxy060608's avatar
fxy060608 已提交
133
    args.push(colors.yellow(pad(err.frame)))
fxy060608's avatar
fxy060608 已提交
134 135 136 137 138
  }
  if (includeStack && err.stack) {
    args.push(pad(cleanStack(err.stack)))
  }
  return args.join('\n')
fxy060608's avatar
fxy060608 已提交
139 140
}

fxy060608's avatar
fxy060608 已提交
141 142 143 144 145
function cleanStack(stack: string) {
  return stack
    .split(/\n/g)
    .filter((l) => /^\s*at/.test(l))
    .join('\n')
fxy060608's avatar
fxy060608 已提交
146
}
fxy060608's avatar
fxy060608 已提交
147

fxy060608's avatar
fxy060608 已提交
148 149 150 151 152
const splitRE = /\r?\n/

function pad(source: string, n = 2): string {
  const lines = source.split(splitRE)
  return lines.map((l) => ` `.repeat(n) + l).join(`\n`)
fxy060608's avatar
fxy060608 已提交
153
}