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)开发过程中还遇到一个升级的问题,确实需要耗费很多精力。