webpack是什么,作用是什么
官网定义:本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。
源码:https://github.com/webpack/webpack
工作方式:webpack会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
简单的来说,WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。在开发蜂巢指纹浏览器(NestBrowser)就不可避免需要深入理解webpack。
webpack怎么实现的
源码太复杂,分析起来太麻烦。用一个简单的实现来说明实现原理最有效。
webpack的核心功能分为两步:
1、分析入口js文件,把所有的依赖找出来(包括所有后代的依赖)。其中依赖babel生成AST抽象语法树。次案例我们用的是babel的配套工具来做语法分析和转化,但是真正的webpack用的是webassemblyjs的配套工具。
webassemblyjs官网:webassemblyjs · webassemblyjs
源码:https://github.com/xtuc/webassemblyjs
const fs = require('fs');
const path = require('path');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const { transformFromAST } = require('@babel/core');
// 分析一个文件,转成CommonJS Module,并找出它的依赖
function readCode(filePath) {
// 读取文件字符串
const content = fs.readFileSync(filePath, 'utf-8');
// 语法解析成 AST
const ast = parser(content, {
sourceType: 'module'
})
// 获取本文件的依赖
const dependiences = [];
// 遍历 AST,每当触发依赖钩子,就往依赖数组添加
traverse(ast, {
ImportDeclaration({node}) {
// 把对应的以来路径存起来
dependiences.push(node.source.value)
}
})
// 把 es6 转成 es5 字符串
// 最重要的是把 esModule 的 import export,转成 es5 能认识的 commonJs写法
const { code } = transformFromAST(ast, null, {
presets: ['@babel/preset-env']
})
return {
filePath,
code,
dependiences
}
}
// 广度优先算法,深入找出所有的依赖
function getAllDependencies(filePath) {
const entryObj = readCode(filePath);
const dependencies = [entryObj];
for (const dependency of dependencies) {
const curDirname = path.dirname(dependency.filePath)
for (const relativePath dependency.dependencies) {
const absolutePath = path.join(curDirname, relativePath);
const child = readCode(absolutePath);
child.relativePath = relativePath;
dependencies.push(child);
}
}
return dependencies;
}
2、拼接一个立即执行函数
function bundle(fileName) {
const dependencies = getAllDependencies(fileName);
const modulesStr = '';
dependencies.forEach(dependency => {
const key = dependency.relativePath || dependency.filePath;
modulesStr += `'${key}': function(module, exports, require) {
${ dependency.code }
}`
})
return `(function(modules) {
const installedModules = {};
function require(id) {
// 解决循环依赖
if (installedModules[id]) {
return installedModules[id].exports;
}
var module = installedModules[id] = {exports: {}};
modules[id].call(module.exports, module, module.exports, require);
return module.exports;
}
return require('${fileName}')
})({${modulesStr}})`
}
webpack优势是什么,劣势是什么
优势:
1、webpack 是以 commonJS 的形式来书写脚本的,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。
2、可以通过配置,打包成多个文件,有效利用浏览器的缓存功能提升性能。
3、将样式文件和图片等静态资源也可视为模块进行打包。配合 loader 加载器,可以支持 Sass,Less 等 CSS 预处理器。
4、专注于处理模块化的项目,能做到开箱即用、 一步到位。
5、扩展性强,插件 plugins 机制完善。
利用webpack 蜂巢指纹浏览器(NestBrowser)的可以实现复杂的模块加载和打包。
劣势:
1、配置难&难调试。熟练配置门槛高。错误提示也非常难看懂,基本不可能从错误很直观的找到原因,出错的时候需要花费相当大的精力查找问题。
2、编译慢。经验不足的同学很容易碰到这个问题,当然可以通过一些手段做优化,比如配置module的resolve、root等,使用happypack加速、dll提前编译等等。
3、蜂巢指纹浏览器(NestBrowser)开发过程中还遇到一个升级的问题,确实需要耗费很多精力。