log.ts 3.8 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'
7
import { isString } from '@vue/shared'
fxy060608's avatar
fxy060608 已提交
8
import { normalizePath } from '../utils'
fxy060608's avatar
fxy060608 已提交
9
import { Formatter } from '../logs/format'
fxy060608's avatar
fxy060608 已提交
10 11 12 13

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

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

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

fxy060608's avatar
fxy060608 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
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 已提交
36 37
export const h5ServeFormatter: Formatter = {
  test(msg) {
fxy060608's avatar
fxy060608 已提交
38
    return msg.includes(SIGNAL_H5_LOCAL) || msg.includes(SIGNAL_H5_NETWORK)
fxy060608's avatar
fxy060608 已提交
39 40
  },
  format(msg) {
fxy060608's avatar
fxy060608 已提交
41 42 43
    if (msg.includes(SIGNAL_H5_NETWORK)) {
      networkLogs.push(msg)
      process.nextTick(() => {
fxy060608's avatar
fxy060608 已提交
44 45 46 47 48 49 50
        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 已提交
51 52 53
      })
      return ''
    }
fxy060608's avatar
fxy060608 已提交
54 55 56 57 58 59 60
    return msg.replace('>', '-')
  },
}

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

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

fxy060608's avatar
fxy060608 已提交
92 93 94 95 96 97 98
function buildErrorMessage(
  err: RollupError,
  args: string[] = [],
  includeStack = true
): string {
  if (err.plugin) {
    args.push(
fxy060608's avatar
fxy060608 已提交
99
      `${colors.magenta('[plugin:' + err.plugin + ']')} ${colors.red(
fxy060608's avatar
fxy060608 已提交
100 101 102
        err.message
      )}`
    )
fxy060608's avatar
fxy060608 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
    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 已提交
120
          // correct error location
fxy060608's avatar
fxy060608 已提交
121 122 123 124
          err.loc.line = scriptLoc.start.line + err.loc.line - 1
        }
      } catch (e: any) {}
    }
fxy060608's avatar
fxy060608 已提交
125
  } else {
fxy060608's avatar
fxy060608 已提交
126
    args.push(colors.red(err.message))
fxy060608's avatar
fxy060608 已提交
127 128
  }
  if (err.id) {
fxy060608's avatar
fxy060608 已提交
129
    args.push(formatAtFilename(err.id, err.loc?.line, err.loc?.column))
fxy060608's avatar
fxy060608 已提交
130 131
  }
  if (err.frame) {
fxy060608's avatar
fxy060608 已提交
132
    args.push(colors.yellow(pad(err.frame)))
fxy060608's avatar
fxy060608 已提交
133 134 135 136 137
  }
  if (includeStack && err.stack) {
    args.push(pad(cleanStack(err.stack)))
  }
  return args.join('\n')
fxy060608's avatar
fxy060608 已提交
138 139
}

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

fxy060608's avatar
fxy060608 已提交
147 148 149 150 151
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 已提交
152
}