简易版
问题:在打包的js库中有很多日志或者error的控制台输出,但是打包后的js调用报错后无法从控制台看到堆栈信息,无法定位报错的位置是在哪个文件的哪一行
需求:能够从报错中观察到报错在哪个文件的那一行,便于排查错误
实现:自定义插件来实现此功能
思路:在打包时遍历要打包的文件,将文件内容按照换行符进行分割,得到的集合就是这个文件的代码,便可以拿到行号,然后通过正则表达式对占位符进行全局替换。
代码:
- replace.js
// 导入path包获取文件名,也可以通过正则来自己获取
import path from 'path';
export default function replace(options = {}) {
const { placeholders = [] } = options;
let fileCount = 0;
let replaceCount = 0;
return {
//插件名
name: 'placeholder-replace',
transform(code, id) {
// 将代码转换为 UTF-8 编码
code = code.toString('utf-8');
// 获取文件名
const fileName = path.basename(id);
// 遍历每个占位符
code = placeholders.reduce((modifiedCode, placeholder) => {
// 构建占位符的正则表达式
const placeholderRegex = new RegExp(`${placeholder}`, 'g');
return modifiedCode
.split('\n')
.map((line, row) => {
let newLine = '';
let cursor = 0;
let result;
while ((result = placeholderRegex.exec(line))) {
const col = result.index;
// 替换占位符为文件名:行号=>>的形式
newLine += line.slice(cursor, result.index) + `${fileName}:${row + 1} =>> `;
cursor += col + result[0].length;
}
newLine += line.slice(cursor);
return newLine;
})
.join('\n');
}, code);
return code;
},
buildEnd() {
console.log(`\n替换的文件数: ${fileCount}`);
console.log(`\n替换的次数: ${replaceCount}`);
},
};
}
配置:
import replace from './replace.js';
export default {
// ...其他配置项
plugins: [
replace({
placeholders: ['log-position-placeholder', 'another-placeholder'], // 设置占位符数组
}),
],
};
进阶版
使用简易版的存在一个问题, 打包后生成的sourceMap文件中的映射内容是空的,如果不需要这个文件的可以使用简易版的,进阶版则是完善了这个问题的解决
代码
replcae.js文章来源:https://www.toymoban.com/news/detail-573373.html
import path from 'path';
// 导入 rollup-pluginutils 包,它提供了一些工具函数来处理 sourcemap
import {createFilter} from 'rollup-pluginutils';
// 导入 magic-string 包,它可以让你修改字符串并生成 sourcemap
import MagicString from 'magic-string';
export default function replace(options = {}) {
const {placeholders = []} = options;
let fileCount = 0;
let replaceCount = 0;
// 使用 createFilter 函数来过滤掉不需要处理的文件
const filter = createFilter(options.include, options.exclude);
return {
// 插件名
name: 'placeholder-replace',
transform(code, id) {
// 如果文件不符合过滤条件,直接返回
if (!filter(id)) return null;
// 将代码转换为 UTF-8 编码
code = code.toString('utf-8');
// 创建一个 MagicString 对象,用于修改代码和生成 sourcemap
const magicString = new MagicString(code);
// 获取文件名
const fileName = path.basename(id);
// 遍历每个占位符
placeholders.forEach(placeholder => {
// 构建占位符的正则表达式
const placeholderRegex = new RegExp(`${placeholder}`, 'g');
let result;
while ((result = placeholderRegex.exec(code))) {
const start = result.index;
const end = start + result[0].length;
// 获取行号和列号
const line = getRow(result.input, start, '\n');
// 替换占位符为文件名:行号=>>的形式
magicString.overwrite(start, end, `${fileName}:${line} =>> `);
replaceCount++;
}
});
fileCount++;
// 返回修改后的代码和 sourcemap 对象
return {
code: magicString.toString(),
map: magicString.generateMap({hires: true})
};
},
buildEnd() {
console.log(`\n替换的文件数: ${fileCount}`);
console.log(`\n替换的次数: ${replaceCount}`);
},
};
}
/**
* 获取行号
* @param str 代码内容
* @param end 截止位置
* @param tag 换行符
* @return {number} 行号
*/
function getRow(str, end, tag) {
let slice = str.slice(0, end);
let split = slice.split(tag);
let length = split.length;
return length;
}
扩展版
import path from 'path';
// 导入 rollup-pluginutils 包,它提供了一些工具函数来处理 sourcemap
import {createFilter} from 'rollup-pluginutils';
// 导入 magic-string 包,它可以让你修改字符串并生成 sourcemap
import MagicString from 'magic-string';
/**
*文件内容替换: 两个关键字fileName,row
* @param options: {handles:
* [{src: '', 待替换的字符串
* target: ''}], 目标字符串
* include: '', 包含的文件
* exclude: ''} 排除的文件
*
* 示例配置: replace({
handles: [{src: 'log-position-placeholder'}, {src: 'console\\.log\\(', target: 'console.log("调试输出: fileName:row ==> " +'}], // 设置占位符数组
})
将log-position-placeholder替换成文件名加行号,以及将console.log( 替换成 console.log("调试输出: 文件名加行号
注意src里面的特殊符合需要用两个\\来进行转义
* @return
*/
export default function replace(options = {}) {
options = Object.assign({handles: [{src: '', target: ''}]}, options);
let fileCount = 0;
let replaceCount = 0;
// 使用 createFilter 函数来过滤掉不需要处理的文件
const filter = createFilter(options.include, options.exclude);
return {
// 插件名
name: 'placeholder-replace',
transform(code, id) {
// 如果文件不符合过滤条件,直接返回
if (!filter(id)) return null;
// 将代码转换为 UTF-8 编码
code = code.toString('utf-8');
// 创建一个 MagicString 对象,用于修改代码和生成 sourcemap
const magicString = new MagicString(code);
// 获取文件名
const fileName = path.basename(id);
// 遍历每个占位符
options.handles.forEach(handle => {
// 构建占位符的正则表达式
const placeholderRegex = new RegExp(`${handle.src}`, 'g');
let result;
while ((result = placeholderRegex.exec(code))) {
const start = result.index;
const end = start + result[0].length;
// 获取行号和列号
const line = getRow(result.input, start, '\n');
// 替换占位符为文件名:行号=>>的形式
let target = handle.target;
if (target) {
target = target.indexOf('row') !== -1 ? target.replace('row', line) : target;
target = target.indexOf('fileName') !== -1 ? target.replace('fileName', fileName) : target;
} else {
target = `${fileName}:${line} =>> `;
}
magicString.overwrite(start, end, target);
replaceCount++;
}
});
fileCount++;
// 返回修改后的代码和 sourcemap 对象
return {
code: magicString.toString(),
map: magicString.generateMap({hires: true})
};
},
buildEnd() {
console.log(`\n替换的文件数: ${fileCount}`);
console.log(`\n替换的次数: ${replaceCount}`);
},
};
}
/**
* 获取行号
* @param str 代码内容
* @param end 截止位置
* @param tag 换行符
* @return {number} 行号
*/
function getRow(str, end, tag) {
let slice = str.slice(0, end);
let split = slice.split(tag);
let length = split.length;
return length;
}
配置:
配置和简易版是一样的,只是增加了一个包含和排除掉选项文章来源地址https://www.toymoban.com/news/detail-573373.html
扩展:
- 除了 transform钩子函数之外,Rollup 还提供了其他一些常用的钩子函数,用于在构建过程中执行特定的逻辑。以下是一些常用的钩子函数:
buildStart:在构建过程开始时调用,可以在其中执行一些初始化操作。
buildEnd:在构建完成后调用。
resolveId:在解析模块标识符时调用,可以自定义模块的解析逻辑。
load:在加载模块时调用,可以自定义模块的加载逻辑。
transform:在转换模块代码时调用,可以修改模块的代码内容。
renderStart:在开始渲染生成输出文件时调用,可以执行一些准备工作。
renderChunk:在渲染每个输出块(chunk)时调用,可以修改输出块的代码内容。
renderDynamicImport:在渲染动态导入语句时调用,可以自定义动态导入的行为。
writeBundle:在生成输出文件完成后调用,可以执行一些清理或后处理的操作。
这些钩子函数可以根据需要选择使用,并根据特定的构建过程进行定制。你可以根据自己的需求在插件配置中添加这些钩子函数,并在相应的钩子函数中编写你想要的逻辑。
到了这里,关于rollup打包js库 占位符替换成文件名和行号输出日志中定位报错位置的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!