webpack把react编译成weapp
引言
webpack入口
webpack
@5.69.0
之前使用taro@3.5.5
创建一个taro-react项目之后build了一个weapp项目
最后一步就是启用webpack
把react
代码编译成weapp
webpack入口
在package.json
中可以找到入口文件
这个文件的作用就是引入webpack核心函数
(lib/webpack.js)以及工具文件,抛出整理好之后的webpack核心函数
"main": "lib/index.js",
最终输出:
// lib/index.js
// mergeExports是处理fn的,最后输出的就是结果处理的fn
module.exports = mergeExports(fn, {
// 很多webpack内置插件
get webpack() {
return require("./webpack"); // 核心文件
},
......
})
mergeExports
// lib/index.js
// 第一个参数是对象(函数继承于Fuction,Fuction继承于Object)
const mergeExports = (obj, exports) => {
// 克隆exports对象,传入这个对象里有很多的文件的引入
const descriptors = Object.getOwnPropertyDescriptors(exports);
// 遍历这个对象
for (const name of Object.keys(descriptors)) {
const descriptor = descriptors[name];
if (descriptor.get) {
const fn = descriptor.get;
// 遍历出的属性一个个添加getter到传入的webpack函数
Object.defineProperty(obj, name, {
configurable: false,
enumerable: true,
/**
* memoize就是执行了传入的fn返回一个返回执行之后的结果的一个函数
* memoize(fn)等于
* function(){
* return fn();
* }
*/
get: memoize(fn)
});
} else if (typeof descriptor.value === "object") {
Object.defineProperty(obj, name, {
configurable: false,
enumerable: true,
writable: false,
value: mergeExports({}, descriptor.value) // 递归
});
} else {
throw new Error(
"Exposed values must be either a getter or an nested object"
);
}
}
// 返回了一个冻结之后的对象,这个对象是个函数,函数里面有很多添加进去的属性方法
return /** @type {A & B} */ (Object.freeze(obj));
};
打印descriptor
可以得到如下
{
get: [Function: get webpack],
set: undefined,
enumerable: true,
configurable: true
}
...
{
value: {
ModuleDependency: [Getter],
ConstDependency: [Getter],
NullDependency: [Getter]
},
writable: true,
enumerable: true,
configurable: true
}
...
打印最终返回的
[Function: f] {
webpack: [Getter],
validate: [Getter],
validateSchema: [Getter],
version: [Getter],
cli: [Getter],
AutomaticPrefetchPlugin: [Getter],
AsyncDependenciesBlock: [Getter],
BannerPlugin: [Getter],
Cache: [Getter],
Chunk: [Getter],
ChunkGraph: [Getter],
CleanPlugin: [Getter],
Compilation: [Getter],
Compiler: [Getter],
ConcatenationScope: [Getter],
ContextExclusionPlugin: [Getter],
ContextReplacementPlugin: [Getter],
DefinePlugin: [Getter],
DelegatedPlugin: [Getter],
Dependency: [Getter],
DllPlugin: [Getter],
DllReferencePlugin: [Getter],
DynamicEntryPlugin: [Getter],
EntryOptionPlugin: [Getter],
EntryPlugin: [Getter],
EnvironmentPlugin: [Getter],
EvalDevToolModulePlugin: [Getter],
EvalSourceMapDevToolPlugin: [Getter],
ExternalModule: [Getter],
ExternalsPlugin: [Getter],
Generator: [Getter],
HotUpdateChunk: [Getter],
HotModuleReplacementPlugin: [Getter],
IgnorePlugin: [Getter],
JavascriptModulesPlugin: [Getter],
LibManifestPlugin: [Getter],
LibraryTemplatePlugin: [Getter],
LoaderOptionsPlugin: [Getter],
LoaderTargetPlugin: [Getter],
Module: [Getter],
ModuleFilenameHelpers: [Getter],
ModuleGraph: [Getter],
ModuleGraphConnection: [Getter],
NoEmitOnErrorsPlugin: [Getter],
NormalModule: [Getter],
NormalModuleReplacementPlugin: [Getter],
MultiCompiler: [Getter],
Parser: [Getter],
PrefetchPlugin: [Getter],
ProgressPlugin: [Getter],
ProvidePlugin: [Getter],
RuntimeGlobals: [Getter],
RuntimeModule: [Getter],
SingleEntryPlugin: [Getter],
SourceMapDevToolPlugin: [Getter],
Stats: [Getter],
Template: [Getter],
UsageState: [Getter],
WatchIgnorePlugin: [Getter],
WebpackError: [Getter],
WebpackOptionsApply: [Getter],
WebpackOptionsDefaulter: [Getter],
WebpackOptionsValidationError: [Getter],
ValidationError: [Getter],
cache: { MemoryCachePlugin: [Getter] },
config: {
getNormalizedWebpackOptions: [Getter],
applyWebpackOptionsDefaults: [Getter]
},
dependencies: {
ModuleDependency: [Getter],
ConstDependency: [Getter],
NullDependency: [Getter]
},
ids: {
ChunkModuleIdRangePlugin: [Getter],
NaturalModuleIdsPlugin: [Getter],
OccurrenceModuleIdsPlugin: [Getter],
NamedModuleIdsPlugin: [Getter],
DeterministicChunkIdsPlugin: [Getter],
DeterministicModuleIdsPlugin: [Getter],
NamedChunkIdsPlugin: [Getter],
OccurrenceChunkIdsPlugin: [Getter],
HashedModuleIdsPlugin: [Getter]
},
javascript: {
EnableChunkLoadingPlugin: [Getter],
JavascriptModulesPlugin: [Getter],
JavascriptParser: [Getter]
},
optimize: {
AggressiveMergingPlugin: [Getter],
AggressiveSplittingPlugin: [Getter],
InnerGraph: [Getter],
LimitChunkCountPlugin: [Getter],
MinChunkSizePlugin: [Getter],
ModuleConcatenationPlugin: [Getter],
RealContentHashPlugin: [Getter],
RuntimeChunkPlugin: [Getter],
SideEffectsFlagPlugin: [Getter],
SplitChunksPlugin: [Getter]
},
runtime: {
GetChunkFilenameRuntimeModule: [Getter],
LoadScriptRuntimeModule: [Getter]
},
prefetch: { ChunkPrefetchPreloadPlugin: [Getter] },
web: {
FetchCompileAsyncWasmPlugin: [Getter],
FetchCompileWasmPlugin: [Getter],
JsonpChunkLoadingRuntimeModule: [Getter],
JsonpTemplatePlugin: [Getter]
},
webworker: { WebWorkerTemplatePlugin: [Getter] },
node: {
NodeEnvironmentPlugin: [Getter],
NodeSourcePlugin: [Getter],
NodeTargetPlugin: [Getter],
NodeTemplatePlugin: [Getter],
ReadFileCompileWasmPlugin: [Getter]
},
electron: { ElectronTargetPlugin: [Getter] },
wasm: { AsyncWebAssemblyModulesPlugin: [Getter] },
library: { AbstractLibraryPlugin: [Getter], EnableLibraryPlugin: [Getter] },
container: {
ContainerPlugin: [Getter],
ContainerReferencePlugin: [Getter],
ModuleFederationPlugin: [Getter],
scope: [Getter]
},
sharing: {
ConsumeSharedPlugin: [Getter],
ProvideSharedPlugin: [Getter],
SharePlugin: [Getter],
scope: [Getter]
},
debug: { ProfilingPlugin: [Getter] },
util: {
createHash: [Getter],
comparators: [Getter],
runtime: [Getter],
serialization: [Getter],
cleverMerge: [Getter],
LazySet: [Getter]
},
sources: [Getter],
experiments: {
schemes: { HttpUriPlugin: [Getter] },
ids: { SyncModuleIdsPlugin: [Getter] }
}
}
fn:
// lib/index.js
// fn懒加载出来的webpack核心函数
const fn = lazyFunction(() => require("./webpack"));
lazyFunction:这里我们可以知道webpack核心函数(lib/webpack)
是怎么接受参数的
// lib/index.js
const lazyFunction = factory => {
// 和mergeExports一样返回一个返回执行了factory后的函数
const fac = memoize(factory); // fac函数一个函数
const f = (
// 这里args就是我们传入的webpack配置参数
(...args) => {
/**
* fac() 等于 factory()
* fac()(...args) 等于 factory()(...args)
* factory 等于 () => require("./webpack")
* require("./webpack")(...args)
*/
return fac()(...args);
}
);
return (f);// 最后返回f这个函数,在mergeExports里getter添加之后作为入口抛出,在前端工程化项目中webpack启动器里传入webpack配置参数执行
};
webpack.jslib/webpack.js
抛出编译器(有callback则执行编译器编译)
webpack
方法 主方法,抛出编译器compiler(有callback则执行编译器编译)options
是一个webpack配置对象或者配置对象数组,回调函数callback
,有callback
就可以在这里直接编译,没有则需要外部调用compiler.run()
在《build一个weapp》的packages/taro-webpack5-runner/src/index.mini.ts中 const compiler = webpack(webpackConfig)
没有传callback
只传了webpack配置
,正好在webpack启动器里调用了run、watch、close
方法
// lib/webpack.js
const webpack = (options, callback) => {
// create返回一个对象对象里有编译器、是否监听、监听参数
const create = () => {
// options作为数组然后用webpackOptionsSchemaCheck校验参数
if (!asArray(options).every(webpackOptionsSchemaCheck)) { // false
...
}
let compiler; // MultiCompiler多个编译器或Compiler单个编译器
let watch = false; // 是否热更新监听,只要有一个webpack配置是热更新就监听
let watchOptions; // 热更新监听的参数可以是对象也可以是个对象数组
if (Array.isArray(options)) {
compiler = createMultiCompiler(options,options);
watch = options.some(options => options.watch);
watchOptions = options.map(options => options.watchOptions || {});
} else {
const webpackOptions = options;
compiler = createCompiler(webpackOptions);
watch = webpackOptions.watch;
watchOptions = webpackOptions.watchOptions || {};
}
return { compiler, watch, watchOptions };
};
if (callback) {
try {
const { compiler, watch, watchOptions } = create();
if (watch) {
// 开始监听
compiler.watch(watchOptions, callback);
} else {
// 开始编译
compiler.run((err, stats) => {
compiler.close(err2 => {
callback(err || err2, stats);
});
});
}
// 抛出编译器
return compiler;
} catch (err) {
process.nextTick(() => callback(err));
return null;
}
} else {
const { compiler, watch } = create();
if (watch) {
util.deprecate(
() => {},
"A 'callback' argument needs to be provided to the 'webpack(options, callback)' function when the 'watch' option is set. There is no way to handle the 'watch' option without a callback.",
"DEP_WEBPACK_WATCH_WITHOUT_CALLBACK"
)();
}
// 抛出编译器
return compiler;
}
};
createCompiler
创建一个编译器
// 参数就是webpack配置参数对象
const createCompiler = rawOptions => {
// 把webpack配置参数标准化
const options = getNormalizedWebpackOptions(rawOptions);
// 基础参数的初始化,这里只给日志输出格式和options.context(项目地址路径)进行了赋值
applyWebpackOptionsBaseDefaults(options);
// 实例化Compiler编译器
const compiler = new Compiler(options.context, options);
// 拓展compiler,注册beforeRun钩子,添加对文件的缓存、监听、输入输出
new NodeEnvironmentPlugin({
infrastructureLogging: options.infrastructureLogging
}).apply(compiler);
// 注册plugin插件this指向编译器compiler,重新注册一遍插件
if (Array.isArray(options.plugins)) {
for (const plugin of options.plugins) {
if (typeof plugin === "function") {
plugin.call(compiler, compiler);
} else {
plugin.apply(compiler);
}
}
}
// 基础参数的初始化
applyWebpackOptionsDefaults(options);
// 执行environment钩子和afterEnvironment钩子
compiler.hooks.environment.call();
compiler.hooks.afterEnvironment.call();
// 注册内置插件,lib/index.js中的第二个参数
new WebpackOptionsApply().process(options, compiler);
// 执行initialize钩子
compiler.hooks.initialize.call();
return compiler;
};
版权声明
本文仅代表作者观点,不代表博信信息网立场。