当我们谈论vite时,我们在谈论什么(从零上手!)

作者:supot

原文:https://juejin.cn/post/6962902504212267021

前言

在ES6之前,JavaScript没有一个标准的模块方案,社区比较流行的是AMD方案和node使用的CommonJS的方案。

为了能够在浏览器端使用npm上大量的CommonJS规范的包,需要我们去对模块进行兼容和处理,这就是前端打包需要解决的一个问题。

Webpack

Webpack是现在主流的打包工具,不管是蚂蚁的umi还是vue的vue-cli,底层都是基于Webpack来进行二次封装的。

Webpack 官方将它定位为一个 module bundler,它通过定义的入口文件,进行依赖收集,构建出项目的依赖图,最后生成并输出一个或多个bundle。

下图是官方给出的Webapck对于模块的处理流程

当我们谈论vite时,我们在谈论什么(从零上手!)_第1张图片

一个能在浏览器中运行的模块系统

我们希望浏览器能够顺利的运行第三方的包和业务代码,不管是commonjs、requirejs或者是es6的模块,所以需要提供一个新的模块系统,将这些第三方包和项目里的业务模块进行统一处理,以便在浏览器中能正确的运行。

webpack 用类似于node 的commonjs的模块方案,将最终打包的代码运行在浏览器中。

(function(modules) { // webpackBootstrap
    // 已经加载的模板
    var installedModules = {};

    // 模块加载函数
    function __webpack_require__(moduleId) {
      // ...
    }

    // 入口文件
    return __webpack_require__(__webpack_require__.s = "./index.js");
  })
  ({
    "./index.js": (function(module, __webpack_exports__, __webpack_require__) {}),
    "./utils/test.js": (function(module, __webpack_exports__, __webpack_require__) {})
  });
复制代码

上面就是webpack打包出来的代码,其中index.js是项目的入口文件,所以的模块都通过 __webpack_require__ 进行加载,并且会把加载完成的模块进行缓存。

var installedModules = {};

// The require function
function __webpack_require__(moduleId) {
  // Check if module is in cache
  if(installedModules[moduleId]) {
    return installedModules[moduleId].exports;
  }
  // Create a new module (and put it into the cache)
  var module = installedModules[moduleId] = {
    i: moduleId, // Module ID
    l: false, //
    exports: {}
  };

  // Execute the module function
  modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

  // Flag the module as loaded
  module.l = true;

  // Return the exports of the module
  return module.exports;
}

通过__webpack_require_的代码可以看出,webpack实现了一个类似CommonJS的模块方案。

插件系统

对于webpack来说,如果仅仅解决不同方案模块的聚合和运行,是远远不够的。对于越来越复杂的前端项目,需要提供更加底层的能力给开发者,去实现不同业务场景的不同需求。

Webpack 基于 Tapable 实现了一个复杂的插件系统,在它的构建过程中,对外抛出了各个关键的节点的hook,开发者可以通过订阅这些勾子,对webpack中的资源进行加工和处理,从而完成定制化的需求

通过Plugin和Loader,能够不断扩展Webpack的功能。

当我们谈论vite时,我们在谈论什么(从零上手!)_第2张图片

存在的问题

当然,Webpack 也不是十全十美的,在学习和试用过程中,也会存在大大小小的问题

  • 概念和配置项太多,需要配合实际的项目场景不断的优化配置文件,umi、vue-cli等脚手架就是为了解决无法开箱即用的问题

  • 随着项目的不断变大,devServer的启动时间会越来越长,并且hmr的速度也会受到影响

  • 功能缺失,在webpack5之前,没有系统级别的文件缓存系统

契机的出现

契机一:http/2

由于http/2的普及,使得很多基于http/1的优化工作都变成了反模式,其中最主要的一条就是合并代码减少网络请求。

因为在http/1的时代,浏览器只能并行的发起5个请求,这就造成如果文件太多,会存在请求阻塞的问题,所以在很多项目中,我们都会去对代码进行打包生成尽量少的vendor。但是在http/2里,所有的请求都会在一个tcp链接里面完成,并且资源都是并行加载的,这时候单个大文件的加载时间反而会比多个小文件的时间要多。所以在http/2的网络里,我们需要对项目资源进行合理的拆分,充分利用资源的并行请求来减少资源的加载时间。

契机二:ES Module

在es6中,加入了JavaScript的模块。

只需要在script标签上加上 type=module 的属性,浏览器就会将内联代码或者外部引用的脚本视为ECMAScript模块。

相比于 Node 的 CommonJS 模块,ES Module 有很多的不同:

  • ES module 抛出的是一个引用,而exports抛出的是一个值

  • require 可以进行动态引用,而ES module需要在作用域的顶层声明所有的依赖,这就导致Node是可以在运行时去加载模块的, 而ES module可以在编译阶段就完成所有的依赖分析,并为后面的优化做准备(比如tree shaking)

  • ...

下面的代码可以在浏览器中直接运行

// test.js
export default function hello() {
  console.log('hello world');
}

// index.html

                    
                    

你可能感兴趣的:(vue,编程语言,javascript,java,人工智能)