webpack相关问题

# webpack相关问题

  • webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能

# 问题1:Loader和Plugin的区别

  • Loader:文件处理,转码,格式转换,文件转换,加载器,加载和解析-eg:ccss转css,es6转es5
  • Plugin:扩展插件,扩展器,压缩文件--eg:uglifyjs-webpack-plugin,通过UglifyES压缩ES6代码

# 问题2:常见的Loader及其作用

  • babel-loader:把 ES6 转换成 ES5
  • css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
  • optimize-css-assets-webpack-plugin:压缩css
  • style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
  • eslint-loader:通过 ESLint 检查 JavaScript 代码
  • html-webpack-plugin:生成的html页面
  • uglifyjs-webpack-plugin:压缩js,开启文件缓存和使用多进程
  • compression-webpack-plugin:gzip压缩

# 问题3:常用Plugin及其作用

  • commons-chunk-plugin:提取公共代码
  • uglifyjs-webpack-plugin:通过UglifyES压缩ES6代码

# 问题4:webpack的构建流程

  • 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数
  • 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译
  • 确定入口:根据配置中的 entry 找出所有的入口文件
  • 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
  • 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统

# 问题5:webpack打包过程,手写打包过程

打包过程:

  • 获取模块内容
  • 分析模块--@babel/parse,转AST--parser.parse()
  • 处理模块--@babel/traverse,遍历AST,收集依赖(res.node.source.value),用ImportDeclaration来解析import - --@babel/core@babel/preset-env--es6转es5
  • 递归模块--广度优先遍历
  • 生成代码--JSON.stringify()后,require,localRequire,eval—自执行函数

Image Text

手写代码

// index.js
import test from './test.js'
import test2 from './test2.js'

console.log(test, test2, 555)
1
2
3
4
5
// test.js
console.log('test777')
let test = 123
export default test
1
2
3
4
// test2.js
console.log('test888')
let tests2 = 456
export default tests2
1
2
3
4
// 核心
// webpack.js
const fs = require('fs')
// 转AST
const parser = require('@babel/parser')
// 遍历ast,收集依赖
// 注意要用.default,使用当前api解析
const traverse = require('@babel/traverse').default
// es6转es5
const { transformFromAst } = require('@babel/core')

function webpack(entry) {
        // 读出utf-8的文件
        const file = fs.readFileSync(entry, 'utf-8')
        // 文件转ast树
        const ast = parser.parse(file, { sourceType: 'module' })
        // 遍历ast,收集依赖
        const dependencies = []
        traverse(ast, {
                // 解析import
                ImportDeclaration(res) {
                        // console.log(res, '解析的import')
                        // 依赖的值
                        const val = res.node.source.value
                        // './test'
                        dependencies.push(val)
                        // ['./test']
                }
        })
        const { code } = transformFromAst(ast, null, {
                presets: ['@babel/preset-env']
        })
        return {
                code,
                dependencies,
                entry
        }
}

// 广度优先遍历,查找所有模块输出,通过执行webpack方法输出
function breadthFirstTraversal(entry) {
        const oneObjs = webpack(entry)
        const graph = {}   //收集所有 {code,dependencies,fileName}
        const allArr = [oneObjs]
        graph[entry] = oneObjs
        while (allArr.length) {
                const oneObj = allArr[0];
                const dependencies = oneObj.dependencies;
                for (let dep of dependencies) {
                        const item = webpack(dep)
                        allArr.push(item)
                        graph[dep] = item
                }
                allArr.shift()
        }
        return graph
}

// 拼写字符串,让浏览器可以递归运行对象里的每一段code
function getJsString(entry) {
        // 获取到的模块对象
        const getObj = breadthFirstTraversal(entry);
        // console.log(getObj, 'getObj')
        // 编写require进行递归
        return `(function(getObj) {
      function require(module) {
        function localRequire(relative) {
          return require(relative)
        };
        
        var exports = {};
        
        (function(require, exports, code) {
          eval(code)
        })(localRequire, exports, getObj[module].code);
        
        return exports;
      };
      
      require('${entry}')
    })(${JSON.stringify(getObj)})`
}

const res= webpack('./index.js')
const deps2 = breadthFirstTraversal('./index.js')
const res2 = getJsString('./index.js')
// console.log(res, 999)
// console.log(deps2, 999)
console.log(res2, 999)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

输出结果:

Image Text