外国人做的网站wordpress主题大全
news/
2025/9/30 11:07:28/
文章来源:
外国人做的网站,wordpress主题大全,网络运营是什么工作,哪些网站可以做问卷文章目录 rollup watch 实现流程watchWatchEmitter 实现 watchInternalWatcher 管理整个 watch 阶段Task 运行任务FileWatcher 实现文件监听 rollup watch 实现流程
每一个配置了 watch 的配置项都会变成一个 Task 任务#xff0c;每个任务通过 FileWatcher 即 chokidar 进行… 文章目录 rollup watch 实现流程watchWatchEmitter 实现 watchInternalWatcher 管理整个 watch 阶段Task 运行任务FileWatcher 实现文件监听 rollup watch 实现流程
每一个配置了 watch 的配置项都会变成一个 Task 任务每个任务通过 FileWatcher 即 chokidar 进行监听需要监听的文件依赖有两种 一种是文件自身 import 的依赖会被放进 dependencies 属性里一种是文件在被插件处理的过程中通过 this.addWatchFile 时watch 的文件会放进该模块的 transformDependencies 属性里 插件里调用 this.emitFile 生成的文件会放进该模块的 transformFiles 属性里 每个 Task 通过 Watcher 进行管理
rollup 打包结果其中一个文件数据结构
{assertions: {},ast: {// 当前模块 ast },code: import _createClass from \babel/runtime/helpers/createClass\;\nimport _classCallCheck from \babel/runtime/helpers/classCallCheck\;\nimport _defineProperty from \babel/runtime/helpers/defineProperty\;\nimport \core-js/modules/es7.array.includes.js\;\nimport a from \a-test\;\nimport foo from \./foo.js\;\nimport packageJosn from \./package.json\;\nvar b require(\path\);\nvar fn function fn() {\n console.log(\index fn243\, a);\n console.log(packageJosn.version);\n console.log(b);\n};\nfn();\nvar A /*#__PURE__*/_createClass(function A() {\n _classCallCheck(this, A);\n _defineProperty(this, \a\, void 0);\n this.a \ww2\;\n});\nvar aa new A();\nvar res [];\nconsole.log(res.includes(\ff\));\nconsole.log(foo);\nexport default fn;,customTransformCache: false,dependencies: [/Users/xxx/Desktop/demo/node_modules/babel/runtime/helpers/esm/createClass.js,/Users/xxx/Desktop/demo/node_modules/babel/runtime/helpers/esm/classCallCheck.js,/Users/xxx/Desktop/demo/node_modules/babel/runtime/helpers/esm/defineProperty.js,core-js/modules/es7.array.includes.js,a-test,/Users/xxx/Desktop/demo/foo.js,/Users/xxx/Desktop/demo/package.json],id: /Users/xxx/Desktop/demo/index.js,meta: {commonjs: {hasDefaultExport: true,isCommonJS: false}},moduleSideEffects: true,originalCode: import a from \a-test\;\nimport foo from \./foo.js\;\nimport packageJosn from \./package.json\;\nconst b require(\path\);\n\nconst fn () {\n console.log(\index fn243\, a);\n console.log(packageJosn.version);\n console.log(b);\n};\nfn();\n\nclass A {\n a;\n constructor() {\n this.a \ww2\;\n }\n}\n\nconst aa new A();\n\nlet res [];\nconsole.log(res.includes(\ff\));\n\nconsole.log(foo);\n\nexport default fn;\n,originalSourcemap: null,resolvedIds: {./package.json: {assertions: {},external: false,id: /Users/xxx/Desktop/demo/package.json,meta: {},moduleSideEffects: true,resolvedBy: node-resolve,syntheticNamedExports: false},core-js/modules/es7.array.includes.js: {assertions: {},external: true,id: core-js/modules/es7.array.includes.js,meta: {},moduleSideEffects: true,resolvedBy: rollup,syntheticNamedExports: false},./foo.js: {assertions: {},external: false,id: /Users/xxx/Desktop/demo/foo.js,meta: {},moduleSideEffects: true,resolvedBy: node-resolve,syntheticNamedExports: false},a-test: {assertions: {},external: true,id: a-test,meta: {},moduleSideEffects: true,resolvedBy: rollup,syntheticNamedExports: false},babel/runtime/helpers/defineProperty: {assertions: {},external: false,id: /Users/xxx/Desktop/demo/node_modules/babel/runtime/helpers/esm/defineProperty.js,meta: {},moduleSideEffects: true,resolvedBy: node-resolve,syntheticNamedExports: false},babel/runtime/helpers/createClass: {assertions: {},external: false,id: /Users/xxx/Desktop/demo/node_modules/babel/runtime/helpers/esm/createClass.js,meta: {},moduleSideEffects: true,resolvedBy: node-resolve,syntheticNamedExports: false},babel/runtime/helpers/classCallCheck: {assertions: {},external: false,id: /Users/xxx/Desktop/demo/node_modules/babel/runtime/helpers/esm/classCallCheck.js,meta: {},moduleSideEffects: true,resolvedBy: node-resolve,syntheticNamedExports: false}},sourcemapChain: [{version: 3,names: [a,foo,packageJosn,b,require,fn,console,log,version,A,_createClass,_classCallCheck,_defineProperty,aa,res,includes],sources: [index.js],sourcesContent: [import a from \a-test\;\nimport foo from \./foo.js\;\nimport packageJosn from \./package.json\;\nconst b require(\path\);\n\nconst fn () {\n console.log(\index fn243\, a);\n console.log(packageJosn.version);\n console.log(b);\n};\nfn();\n\nclass A {\n a;\n constructor() {\n this.a \ww2\;\n }\n}\n\nconst aa new A();\n\nlet res [];\nconsole.log(res.includes(\ff\));\n\nconsole.log(foo);\n\nexport default fn;\n],mappings: [// ...],syntheticNamedExports: false,transformDependencies: [./index2.ts],transformFiles: [{type: asset,source: export default what}]
}watch
当 rollup 配置了 watch 监听文件更改后打包时会调用下面的函数WatchEmitter 和 node emiter 实现类似都是发布订阅 WatchEmitter 是暴露给开发者可以在 rollup watch 各个阶段订阅watchInternal 是 rollup 真正内部进行监听的方法会在各个阶段调用 WatchEmitter 发布
export default function watch(configs: RollupOptions[] | RollupOptions): RollupWatcher {const emitter new WatchEmitter() as RollupWatcher; // 对外暴露给用户注册 watch 过程相关的事件订阅器// 真正内部实现监听的方法watchInternal(configs, emitter).catch(error {handleError(error);});return emitter; // 对外暴露给用户注册的和 watch 相关的 emitter 事件 注册的事件会在 watchInternal 中运行各个阶段触发
}WatchEmitter 实现
import type { AwaitedEventListener, AwaitingEventEmitter } from ../rollup/types;export class WatchEmitterT extends { [event: string]: (...parameters: any) any }implements AwaitingEventEmitterT
{private currentHandlers: {[K in keyof T]?: AwaitedEventListenerT, K[];} Object.create(null);private persistentHandlers: {[K in keyof T]?: AwaitedEventListenerT, K[];} Object.create(null);// Will be overwritten by Rollupasync close(): Promisevoid {}emitK extends keyof T(event: K, ...parameters: ParametersT[K]): Promiseunknown {return Promise.all([...this.getCurrentHandlers(event), ...this.getPersistentHandlers(event)].map(handler handler(...parameters)));}offK extends keyof T(event: K, listener: AwaitedEventListenerT, K): this {const listeners this.persistentHandlers[event];if (listeners) {// A hack stolen from mitt: 0 does not change numbers 0, but -1// (which would remove the last array element if used unchanged) is turned// into max_int, which is outside the array and does not change anything.listeners.splice(listeners.indexOf(listener) 0, 1);}return this;}onK extends keyof T(event: K, listener: AwaitedEventListenerT, K): this {this.getPersistentHandlers(event).push(listener);return this;}onCurrentRunK extends keyof T(event: K, listener: AwaitedEventListenerT, K): this {this.getCurrentHandlers(event).push(listener);return this;}onceK extends keyof T(event: K, listener: AwaitedEventListenerT, K): this {const selfRemovingListener: AwaitedEventListenerT, K (...parameters) {this.off(event, selfRemovingListener);return listener(...parameters);};this.on(event, selfRemovingListener);return this;}removeAllListeners(): this {this.removeListenersForCurrentRun();this.persistentHandlers Object.create(null);return this;}removeListenersForCurrentRun(): this {this.currentHandlers Object.create(null);return this;}private getCurrentHandlersK extends keyof T(event: K): AwaitedEventListenerT, K[] {return this.currentHandlers[event] || (this.currentHandlers[event] []);}private getPersistentHandlersK extends keyof T(event: K): AwaitedEventListenerT, K[] {return this.persistentHandlers[event] || (this.persistentHandlers[event] []);}
}
watchInternal
const optionsList await Promise.all(ensureArray(configs).map(config mergeOptions(config))); // 和内置 options 合并
const watchOptionsList optionsList.filter(config config.watch ! false); // 只拿到配置了 watch 的 options 配置
if (watchOptionsList.length 0) {return error(errorInvalidOption(watch,URL_WATCH,there must be at least one config where watch is not set to false));
}
await loadFsEvents(); // 加载 mac 下的监听文件变化的第三方库fsevents
const { Watcher } await import(./watch); // 真正内部实现监听的 watcher
new Watcher(watchOptionsList, emitter);Watcher 管理整个 watch 阶段
每个 rollup 的打包配置项对应一个 Task 任务Watcher 类的作用就是管理每一个 Task 的运行
export class Watcher {readonly emitter: RollupWatcher;private buildDelay 0;private buildTimeout: NodeJS.Timer | null null;private closed false;private readonly invalidatedIds new Mapstring, ChangeEvent(); // 收集 watch 过程每一次变化的文件 id 及其对应的事件private rerun false;private running true;private readonly tasks: Task[];// optionsList 所有配置了 watch 的 option; emitter 暴露给用户注册 watch 过程相关事件的订阅器constructor(optionsList: readonly MergedRollupOptions[], emitter: RollupWatcher) {this.emitter emitter;emitter.close this.close.bind(this);this.tasks optionsList.map(options new Task(this, options)); // 每一个配置了 watch 的 option 都对应一个 TaskTask 内通过 FileWatcher 实现了通过 chokidar 进行监听for (const { watch } of optionsList) {// 每次重新运行的防抖时间if (watch typeof watch.buildDelay number) {this.buildDelay Math.max(this.buildDelay, watch.buildDelay!);}}// 初始执行process.nextTick(() this.run());}async close(): Promisevoid {if (this.closed) return;this.closed true;if (this.buildTimeout) clearTimeout(this.buildTimeout);for (const task of this.tasks) {task.close();}await this.emitter.emit(close);this.emitter.removeAllListeners();}// 文件变化后调用此函数重新打包invalidate(file?: { event: ChangeEvent; id: string }): void {if (file) {const previousEvent this.invalidatedIds.get(file.id);const event previousEvent ? eventsRewrites[previousEvent][file.event] : file.event;// 为每一个变换了的文件 id 设置对应的事件 delete | add ...if (event buggy) {//TODO: throws or warn? Currently just ignore, uses new eventthis.invalidatedIds.set(file.id, file.event);} else if (event null) {this.invalidatedIds.delete(file.id);} else {this.invalidatedIds.set(file.id, event);}}if (this.running) {this.rerun true;return;}if (this.buildTimeout) clearTimeout(this.buildTimeout);// 定时器防抖触发 rollup 重新 runthis.buildTimeout setTimeout(async () {this.buildTimeout null;try {// 文件变化后触发对应emitterawait Promise.all([...this.invalidatedIds].map(([id, event]) this.emitter.emit(change, id, { event })));this.invalidatedIds.clear();await this.emitter.emit(restart);this.emitter.removeListenersForCurrentRun(); // 取消当前过程注册的所有事件// 重新打包this.run();} catch (error: any) {this.invalidatedIds.clear();await this.emitter.emit(event, {code: ERROR,error,result: null});await this.emitter.emit(event, {code: END});}}, this.buildDelay);}private async run(): Promisevoid {this.running true;await this.emitter.emit(event, {code: START});// 根据配置项重新运行 rollupfor (const task of this.tasks) {await task.run();}this.running false;await this.emitter.emit(event, {code: END});if (this.rerun) {this.rerun false;this.invalidate();}}
}Task 运行任务
每一个配置了 watch 的 rollup 选项都会变成一个单独的 Task每一个Task 都管理每一次运行任务
export class Task {cache: RollupCache { modules: [] };watchFiles: string[] [];private closed false;private readonly fileWatcher: FileWatcher; // 真正去实现监听的 watcherprivate filter: (id: string) boolean; // 过滤监听private invalidated true;private readonly options: MergedRollupOptions;private readonly outputFiles: string[];private readonly outputs: OutputOptions[];private skipWrite: boolean;private watched new Setstring(); // 收集每次监听的文件 idprivate readonly watcher: Watcher; // watcher 为管理 Task 的 Watcherconstructor(watcher: Watcher, options: MergedRollupOptions) {this.watcher watcher; // watcher 为管理 Task 的Watcherthis.options options;// 是否跳过输出文件this.skipWrite Boolean(options.watch options.watch.skipWrite);this.outputs this.options.output;// 解析输出文件地址的路径this.outputFiles this.outputs.map(output {if (output.file || output.dir) return resolve(output.file || output.dir!);return undefined as never;});const watchOptions: WatcherOptions this.options.watch || {};// 创建 watch 中配置了 exclude、include 相关的过滤方法this.filter createFilter(watchOptions.include, watchOptions.exclude);this.fileWatcher new FileWatcher(this, {...watchOptions.chokidar,disableGlobbing: true,ignoreInitial: true});}close(): void {this.closed true;this.fileWatcher.close();}// chokidar 监听到文件变化后触发 id 变化的文件 id; event 对应的文件变化类型; isTransformDependency 当前模块在插件中额外依赖的 idinvalidate(id: string, details: { event: ChangeEvent; isTransformDependency?: boolean }): void {this.invalidated true;// 当前模块在 rollup 打包时插件中添加的依赖模块// 当依赖模块更新后该模块缓存失效清空if (details.isTransformDependency) {for (const module of this.cache.modules) {// 插件里调用 this.addWatchFile 时watch的文件会放进该模块的 transformDependencies 属性里// 插件里调用 this.emitFile 生成的文件会放进该模块的 transformFiles 属性里if (!module.transformDependencies.includes(id)) continue;// effective invalidationmodule.originalCode null as never; // 清除缓存的内容后续重新生成}}this.watcher.invalidate({ event: details.event, id });}async run(): Promisevoid {if (!this.invalidated) return; // 是否在运行中this.invalidated false;const options {...this.options,cache: this.cache};const start Date.now();await this.watcher.emitter.emit(event, {code: BUNDLE_START,input: this.options.input,output: this.outputFiles});let result: RollupBuild | null null;try {result await rollupInternal(options, this.watcher.emitter); // 到此和非 watch 模式下一致if (this.closed) {return;}// 打包完成获取到所有需要监听变化的文件 idthis.updateWatchedFiles(result);this.skipWrite || (await Promise.all(this.outputs.map(output result!.write(output))));await this.watcher.emitter.emit(event, {code: BUNDLE_END,duration: Date.now() - start,input: this.options.input,output: this.outputFiles,result});} catch (error: any) {if (!this.closed) {if (Array.isArray(error.watchFiles)) {for (const id of error.watchFiles) {this.watchFile(id);}}if (error.id) {this.cache.modules this.cache.modules.filter(module module.id ! error.id);}}await this.watcher.emitter.emit(event, {code: ERROR,error,result});}}// 添加打包过程需要的所有监听文件、清除不需要的监听文件private updateWatchedFiles(result: RollupBuild) {const previouslyWatched this.watched;this.watched new Set();// 返回本次打包运行监听的文件 idthis.watchFiles result.watchFiles;// 缓存打包结果this.cache result.cache!;for (const id of this.watchFiles) {this.watchFile(id);}// 获取缓存文件的 idfor (const module of this.cache.modules) {// 在插件中添加的需要观测的依赖for (const depId of module.transformDependencies) {this.watchFile(depId, true);}}// 取消监听上一轮不需要监听的文件 idfor (const id of previouslyWatched) {if (!this.watched.has(id)) {this.fileWatcher.unwatch(id);}}}private watchFile(id: string, isTransformDependency false) {if (!this.filter(id)) return;this.watched.add(id); // 收集每次监听的文件 idif (this.outputFiles.includes(id)) {throw new Error(Cannot import the generated bundle);}// this is necessary to ensure that any renamed files// continue to be watched following an errorthis.fileWatcher.watch(id, isTransformDependency);}
}FileWatcher 实现文件监听
import { platform } from node:os;
import chokidar, { type FSWatcher } from chokidar;
import type { ChangeEvent, ChokidarOptions } from ../rollup/types;
import type { Task } from ./watch;export class FileWatcher {private readonly chokidarOptions: ChokidarOptions;private readonly task: Task;private readonly transformWatchers new Mapstring, FSWatcher(); // 收集所有监听插件中添加的依赖文件的 chokdir watcherprivate readonly watcher: FSWatcher; // 正常的 Task 对应的 chokidar watcherconstructor(task: Task, chokidarOptions: ChokidarOptions) {this.chokidarOptions chokidarOptions; // 用户传递的 chokidar 配置this.task task; // 每一个带有 watch 的 option 对应的 Taskthis.watcher this.createWatcher(null); // 通过 chokidar 监听的实例}close(): void {this.watcher.close();for (const watcher of this.transformWatchers.values()) {watcher.close();}}unwatch(id: string): void {this.watcher.unwatch(id);const transformWatcher this.transformWatchers.get(id);if (transformWatcher) {this.transformWatchers.delete(id);transformWatcher.close();}}watch(id: string, isTransformDependency: boolean): void {// 如果是插件中添加的依赖文件单独生成一个 chokidar watcherif (isTransformDependency) {const watcher this.transformWatchers.get(id) ?? this.createWatcher(id);watcher.add(id);this.transformWatchers.set(id, watcher);} else {this.watcher.add(id);}}// transformWatcherId 区分是否是插件中添加的依赖发生了变化private createWatcher(transformWatcherId: string | null): FSWatcher {const task this.task;const isLinux platform() linux;const isTransformDependency transformWatcherId ! null;// chokidar 监听到文件变化时触发的回调const handleChange (id: string, event: ChangeEvent) {const changedId transformWatcherId || id;if (isLinux) {// unwatching and watching fixes an issue with chokidar where on certain systems,// a file that was unlinked and immediately recreated would create a change event// but then no longer any further eventswatcher.unwatch(changedId);watcher.add(changedId);}// 重新运行打包task.invalidate(changedId, { event, isTransformDependency });};// 通过 chokidar 进行监听const watcher chokidar.watch([], this.chokidarOptions).on(add, id handleChange(id, create)).on(change, id handleChange(id, update)).on(unlink, id handleChange(id, delete));return watcher;}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/922747.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!