当前位置: 首页 > wzjs >正文

附近网站建设公司哪家好网络营销的特点包含

附近网站建设公司哪家好,网络营销的特点包含,诚信网站认证99idc,做网站的软件项目进度计划在现代开发中一般各公司都有自己的监控平台,对前端而言如果浏览器报错的话就可以通过埋点收集错误日志,再结合sourcemap文件可以帮助我们定位到错误代码,帮助我们排查问题。这里就记录一下之前在webpack和vite两个环境中的插件开发&#xff0…

在现代开发中一般各公司都有自己的监控平台,对前端而言如果浏览器报错的话就可以通过埋点收集错误日志,再结合sourcemap文件可以帮助我们定位到错误代码,帮助我们排查问题。这里就记录一下之前在webpack和vite两个环境中的插件开发,可以在生产构建时将sourcemap上传到内部的文件服务器配合后续的监控日志来一起使用

Webpack插件开发

Compiler 和 Compilation

在插件开发中有两个概念比较重要,分别是CompilerCompilation,他们是Plugin和Webpack之间的桥梁。他们的含义如下:

  • Compiler对象包含了Webpack环境所有的配置信息,包含options、loaders、plugins等这些所有的信息,这个对象在Webpack启动的时候被实例化,是全局唯一的,可以把他看成是Webpack的实例
  • Compilation 对象包含了当前模块资源以及编译生成资源还有变化的文件等相关信息。在webpack以开发模式运行时,每当检测到一个文件变化,一个新的Compilation就会被创建。Compilation对象提供了很多事件回调给插件做扩展,通过Compilation也能读取到Compiler对象

两者的区别在于:Compiler代表了整个Webpack从启动到关闭的生命周期,而Compilation只是代表了一次新的编译。

事件流

Webpack 就像一条生产线,要经过一系列处理流程后才能将源文件转换成输出结果。 这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。 插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。
Webpack 通过 Tapable 来组织这条复杂的生产线。 Webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作。 Webpack 的事件流机制保证了插件的有序性,使得整个系统扩展性很好。
Webpack 的事件流机制应用了观察者模式,和 Node.js 中的 EventEmitter 非常相似。 Compiler 和 Compilation 都继承自 Tapable,可以直接在 Compiler 和 Compilation 对象上广播和监听事件。

webpack 插件钩子

每个webpack插件都是一个class,其中最终要的两个内容,一个是constructor,可以接受一个option参数,这个就是用户在使用这个插件时传入的参数,第二个就是apply方法,接受一个compiler这个实例,在webpack初始化时,会调用每个插件,执行其中的apply方法,我们就可以在apply这个方法中使用接受到的Compiler实例上提供的各种hook来监听我们需要的事件,在整个流水线工程中有很多事件钩子,如下图所示:
在这里插入图片描述
我们可以监听我们需要的时机,参考地址Webpack插件钩子
在这里我们需要在webpack打包结束的时候将构建结果中的.map文件上传到自己的文件服务器,所以需要订阅done这个事件钩子,在每次compilation完成时执行。

插件调用方式

在webpack插件中一共有同步和异步两种调用方式,同步调用是直接使用tap异步调用使用tapAsync还有一种是tapPromise,简单代码展示如下:

apply(compiler) {// 同步钩子compiler.hooks.compilation.tap('MyPlugin', (compilation) => {// 同步处理console.log('同步处理');});
}
apply(compiler) {// 异步钩子,使用回调函数compiler.hooks.done.tapAsync('MyPlugin', (stats, callback) => {// 异步处理setTimeout(() => {console.log('异步处理完成');callback();}, 1000);});
}
apply(compiler) {// 异步钩子,返回 Promisecompiler.hooks.done.tapPromise('MyPlugin', (stats) => {return new Promise((resolve) => {setTimeout(() => {console.log('Promise 异步处理完成');resolve();}, 1000);});});
}

这里我们需要将文件上传,所以明显是一个异步的调用,采用的是tapAsync的调用方式,具体代码如下:

const fs = require('fs');
const path = require('path');
const axios = require('axios');
const FormData = require('form-data');// 将打包文件中的.map文件上传到指定服务器
class UploadSourceMapPlugin {constructor(options) {this.options = options;if (!this.options.uploadUrl) {throw new Error('uploadUrl is required');}}apply(compiler) {compiler.hooks.done.tapAsync('UploadSourceMapPlugin', async (stats, callback) => {try {const outputPath = compiler.options.output.path;// 递归读取目录中的所有文件function getAllFiles(dir) {const files = fs.readdirSync(dir);let fileList = [];files.forEach(file => {const filePath = path.join(dir, file);const stat = fs.statSync(filePath);if (stat.isDirectory()) {fileList = fileList.concat(getAllFiles(filePath));} else {fileList.push(filePath);}});return fileList;}// 获取所有文件const allFiles = getAllFiles(outputPath);// 过滤出 .map 文件const sourceMapFiles = allFiles.filter(file => file.endsWith('.map')).map(file => ({name: path.basename(file),path: file}));// 上传所有的 source map 文件for (const file of sourceMapFiles) {const filePath = file.path;if (fs.existsSync(filePath)) {await this.uploadFile(filePath, file.name);// 如果配置了上传后删除if (this.options.deleteAfterUpload) {fs.unlinkSync(filePath);console.log(`Deleted ${file.name} after upload`);}}}// 通知 webpack 异步操作已完成// webpack 可以继续执行后续步骤// 如果不调用 callback,webpack 的构建过程会一直等待callback();} catch (error) {console.error('Error in UploadSourceMapPlugin:', error);callback();}});}async uploadFile(filePath, fileName) {try {const formData = new FormData();formData.append('sourcemap', fs.createReadStream(filePath), fileName);const response = await axios.post(this.options.uploadUrl, formData, {headers: {...formData.getHeaders(),'Authorization': this.options.token || ''  // 可选的认证token}});console.log(`Successfully uploaded ${fileName}`);return response.data;} catch (error) {console.error(`Failed to upload ${fileName}:`, error.message);throw error;}}}module.exports = UploadSourceMapPlugin;

这里有个小小的坑,就是在compiler中有个state对象也是文件列表,但是这里面只能获取到经过Webpack编译之后的文件,所以最保险的还是自己递归遍历一下结果文件进行过滤。这里callback是上传结束之后的回调,告诉webpack已近完成,否则webpack就会一直在这里等待

使用

最终使用这个插件也很简单,我们一般主需要再生产环境使用,开发环境一般是没有必要将sourcemap上传上去的。通过下面的配置就可以使用我们开发的插件了

// 只在生产环境使用...(process.env.NODE_ENV === 'production' ? [new UploadSourceMapPlugin({uploadUrl: 'https://file-server.com/upload',token: 'auth-token',  // 可选的认证tokendeleteAfterUpload: true    // 是否在上传后删除本地文件})] : []),

Vite

Vite 是一个现代的前端构建工具,因其快速、简单的配置和优化的开发体验而广受欢迎。Vite是基于Rollup来的,速度非常快,如果开发的插件不带Vite特有的钩子一般都可以在Rollup中兼容使用。
Vite中的每个插件一般都是一个返回一个对象的函数,其中有name字段表插件名称,以及对应的钩子函数,在Vite中有通用钩子和Vite专属钩子。

在这里插入图片描述
参考地址:Vite插件钩子
这里我们在每次生产环境构建结束时调用这个插件。我们可以用apply: ‘build’, 表示只在构建时调用这个插件,日常开始npm run dev时处于开发状态就不会调用这个插件。
具体代码如下:

import fs from 'fs'
import path from 'path'export default function UploadSourceMapPlugin(options = {}) {const {uploadUrl = '',    // 上传服务器地址headers = {},      // 自定义请求头deleteAfterUpload = true  // 上传后是否删除本地map文件} = optionsif (!uploadUrl) {throw new Error('uploadUrl is required for UploadSourceMapPlugin')}return {name: 'vite-plugin-upload-sourcemap',apply: 'build',    // 仅在构建时应用async closeBundle() {const distDir = path.resolve('dist')const sourcemaps = []// 递归查找所有.map文件function findSourceMaps(dir) {const files = fs.readdirSync(dir)files.forEach(file => {const fullPath = path.join(dir, file)const stat = fs.statSync(fullPath)if (stat.isDirectory()) {findSourceMaps(fullPath)} else if (file.endsWith('.map')) {sourcemaps.push(fullPath)}})}findSourceMaps(distDir)// 上传所有sourcemap文件for (const mapFile of sourcemaps) {const formData = new FormData()formData.append('file', fs.createReadStream(mapFile))try {const response = await fetch(uploadUrl, {method: 'POST',body: formData,headers: {...headers}})if (!response.ok) {throw new Error(`Upload failed for ${mapFile}`)}console.log(`Successfully uploaded: ${mapFile}`)// 如果配置了上传后删除,则删除本地map文件if (deleteAfterUpload) {fs.unlinkSync(mapFile)console.log(`Deleted local file: ${mapFile}`)}} catch (error) {console.error(`Error uploading ${mapFile}:`, error)}}}}
} 

其中的代码逻辑其实和webpack中基本保持一致。至此我们就开发了一个上传soucemap的两套插件可以分别在WebpackRollup中使用了。

参考文件

Webpack插件钩子
Vite插件钩子
Vite插件开发


文章转载自:

http://Atd0YlKl.qgjxy.cn
http://Kkl9hoX4.qgjxy.cn
http://6gjbCxMW.qgjxy.cn
http://QEGjc6WW.qgjxy.cn
http://qKgZd3GW.qgjxy.cn
http://L2VpJlK9.qgjxy.cn
http://RMONfLRX.qgjxy.cn
http://BJZGMMwE.qgjxy.cn
http://2QGTOTT9.qgjxy.cn
http://WMcpLQ2F.qgjxy.cn
http://MYUU1hos.qgjxy.cn
http://HC3lJ2lm.qgjxy.cn
http://ZVNCnEVy.qgjxy.cn
http://fJ13H8LT.qgjxy.cn
http://W5zJJlZD.qgjxy.cn
http://ayj6bJbb.qgjxy.cn
http://HTYyyb44.qgjxy.cn
http://0Na0ApEN.qgjxy.cn
http://4FStcD59.qgjxy.cn
http://mVF4ES7b.qgjxy.cn
http://39Izchcx.qgjxy.cn
http://1kn9ZBIm.qgjxy.cn
http://E5t8Qq6F.qgjxy.cn
http://4Oi1Al11.qgjxy.cn
http://4qRirRzL.qgjxy.cn
http://3rWd5pPd.qgjxy.cn
http://NytpTZGm.qgjxy.cn
http://PNrVyk1O.qgjxy.cn
http://gZ3jvkLe.qgjxy.cn
http://Zveunq2m.qgjxy.cn
http://www.dtcms.com/wzjs/710178.html

相关文章:

  • 成都专业手机网站建设服务ftp给网站上传图片后图片的链接地址被改了
  • 哪个建站软件比较好带论坛深圳十大网络推广公司排名
  • 云南网站推广的目的社区网站建设难点
  • 威龙电子商务做的网站域名网站开发有意义吗
  • google chrome download广东网站建设seo优化制作设计
  • WordPress开网站很慢附近装修公司地址电话
  • 设计网站页面设计西安旅游攻略2天自由行攻略
  • 如何改wordpress网站图标wordpress登录无效用户名
  • 国外设计案例网站无锡网站建设f7wl
  • 做这个网站多少钱pc网站开发微信支付
  • 网站百度指数苏州互联网招聘
  • p2p贷款网站开发网站建设中敬请期待 图片
  • 温州网站关键词排名优化湖南长沙门户网站
  • 蒙自网站开发网站的优势
  • 网站建设策划实施要素有什么网站可以接活做设计
  • 做个网站成本网站备案提交
  • 中冶建设网站邯郸seo优化公司
  • 宁波网站建设营销定制网络营销师报名入口
  • 怎么访问域名网站吗网站重新设计
  • 怎样做网站教程做交互的设计网站
  • 网站多域名建站服务外贸
  • 软件公司招聘网站wordpress友情链接激活
  • 开通公司网站怎么开通企业标志logo设计免费
  • 提供小企业网站建设如何 网站推广
  • 天津网站制作系统百度指数网址
  • 做网站的如何说服客户如何知道一个网站是用什么做的
  • 网站建设的er图怎么画tp框架做的图片网站
  • 产品营销类网站一年四季不愁销路的生意
  • 自己怎么开网站网架公司招聘打板施工队伍
  • 做网站 附加信息eclipse网站建设