Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于 webpack #5

Open
bigbossx opened this issue Jan 14, 2023 · 0 comments
Open

关于 webpack #5

bigbossx opened this issue Jan 14, 2023 · 0 comments
Labels
WIP work in progress

Comments

@bigbossx
Copy link
Owner

bigbossx commented Jan 14, 2023

哎~朋友们好啊,我是练习时长三年半的前端小老板,昨天有个朋友问我,b导师,发生甚么事了,我说怎么回事,给我发了几张截图,我一看,哦,原来是佐天,有两个年轻人,20多岁,一个刚毕业,一个工作一年多了,塔门说,哎~有一个说是,我在天天在src目录下写代码,开发,一点进步都没有,b导师,你能不能教教我webpack相关的知识,哎~帮助学习一下。我说可以,我说你在src目录下练死劲不管用,他不服气。哎~我说小朋友,看我教你怎么跑项目,他说你这也没用。我说我这个有用,这是项目配置,传统前端是讲工程化的,四两拨千金, ​国内国外很多大公司前端项目走的都是这样的流程,他说要我试试,我说可以,哎~我说一完他啪的一下就坐过来了,很快啊!然后我上来就是一个npm install 咳!一个npm start 全部成功了,成功了啊,成功了以后自然是传统前端,8080端口,输在浏览器上没打开,我笑一下准备 ctrol c,因为这时间,按照传统前端的流程,已经打包完了,他也承认,都没报错,他承认是我跑成功了啊,我ctrol c的时间,不跑了,他突然说一句,配置了构建完之后自动打开p站,我大意了啊,没有删,哎~很快就自动打开浏览器,当时很多同事看到了,我说婷婷,但没关系啊,两分多钟之后我关闭了,我说小伙子你不讲伍德,他说b导师对不起对不起,我不懂配置,我是乱加的,他说他是乱加的他可不是乱加的啊,webpack函数 一个配置对象,一个成功回调,训练有素,后来他说他看过几章webpack文档,看来是有备而来,我劝!这位年轻人耗子尾汁,构建,要讲环境,以安全可靠为贵,不要再犯这样的聪明,小聪明啊,谢谢朋友们。

开篇

我们通常将源码 -> 产物的过程称之为打包或者叫构建,在此过程中,我们将获取到源代码内容,重新组装,转换,压缩,混淆,修改...等等一系列的操作,以达到一些非常简单原始的目的:

  • 舒适的开发体验
  • 安全可靠的运行逻辑
  • 良好的用户体验
  • ...

通常来说越复杂的东西,越应该精细化和自动化,工具化等,webpack也是在web应用逐渐复杂的背景下诞生的。

我习惯了解一个东西先去了解时代背景,作者一开始的思想,这样我能更快的知道他为什么做,当时能怎么做,后来怎么做了更多。思路 > 代码实现,当然代码实现仍然是我们非常应该学习然后积累的点。

正文

webpack 开始于2012年 sokra 的一个被拒绝的功能请求 medikoo/modules-webmake#7 基于modules-webmake sokra提出,增加类似Code Splitting的功能。即我们的构建可以有如下的功能:

  • 1、allows you to organize JavaScript code for the browser the same way as you do for Node.js.
  • 2、Code Splitting
  • 3、支持加载 image 和 css

让我们回头来看看,这些是什么,然后在解决什么问题,首先是

Allows you to organize JavaScript code for the browser the same way as you do for Node.js.

我们知道js在esm之前并没有模块规范标准,但是随着web应用的不断复杂化,代码的模块化成为不可或缺的一点,你可以在这些文章详细了解

不再赘述,但我们总结出几个关键点:(在js esm规范之前)
1、AMD CMD 等实现,都有一个函数包裹,即回调函数内,才是模块代码,再详细一点呢?

  • 由于在浏览器环境,网络传输层面的未知延时。我们不能等到const xxx=require("xxx")执行的那一刻才去用script加载xxx.js ,无法同步获取模块的导出
  • 浏览器没有文件内作用域的概念,即在浏览器中a.js b.js 是共享全局变量的,所以仍然是有变量冲突的问题,更没有module这个对象让我们可以在不同js文件中互操作
  • 我们可以将不同的文件内容,通过函数包裹,使用函数作用域解决变量冲突和实现模块之间的导出导入(模块化)

相反nodejs则没有那层函数包裹,module exports require __dirname __filename 都是当前文件的,文件之间变量是隔离的,node是怎么做到的?答案是

  • nodejs 是本地文件的io操作,速度非常快,所以可以等到const xxx=require("xxx")执行那一刻再去初始化xxx模块并获得导出
  • nodejs帮我们隐藏了那层函数包裹。

image

我们从上面的知识已经知道了,不管是AMD CMD还是commonjs,他都是函数包裹的函数作用域
那我们通过构建这一层,使得在开发时去掉这层包裹,由构建工具自动补上,不就跟nodejs一模一样了吗!
所以最终,我们知道了如果我们产物长这个样子,那我们的commonjs风的代码,是可以在浏览器完完整整的运行起来的。即实现了allows you to organize JavaScript code for the browser the same way as you do for Node.js

(function(modules /* 所有可用的模块 */) {
        var installModules = {};
        function magicRequire(id) {
          if (installModules[id]) {
            return installModules[id].exports;
          }
          var module = (installModules[id] = {
            exports: {},
            id: id,
          });
          modules[id](module, module.exports, magicRequire); 
          // modules[id].call(module,module, module.exports, magicRequire); // commonjs 规范,this指向当前模块
          return module.exports;
        }
        magicRequire("entry");
})({
    "entry": function(module, exports, require) {
        var addModule = require("./add");
        const temp = addModule.add(1, 1);
        var { square } = require("./square");
        console.log(square(temp,temp))
    },
    "./add": function(module, exports, require) {
        module.exports = {
            add: function(x, y) {
                return x + y;
            }
        };
    },
    "./square": function(module, exports, require) {
        var { multiply } = require("./multiply");
        module.exports = {
            square: function(num) {
                return multiply(num, num);
            }
        };
    },
    "./multiply": function(module, exports, require) {
        module.exports = {
            multiply: function(x, y) {
                return x * y;
            }
        };
    }
})

这也即是webpack所说的runtime 运行时 + modules 模块,由runtime组织起来module之间的逻辑运行

那Code Splitting是啥

从上面的产物可以知道,这个产物是一个js文件,它不止一个module,所以我们不能再叫module了,给它取了个时兴的名字:chunk 上面这个chunk = runtime + module 。我们可以再进一步把它拆分, runtime 独立出来,叫runtime chunk,modules 部分就叫module chunk吧。

modules就是当前我们所有可用的模块集合,但是,我们的项目可能非常庞大,所以如果将所有的模块组合在同一个js 里面,将会非常大,所以我们需要有组织的将modules 的部分拆分出去。拆分出去的这一部分多个模块组成的js产物文件,我们称为异步chunk

然后我们提供一个类似jsonp的方案,sciprt标签加载异步chunk,通过jsonp回调将额外的module merge 到modules 中,即

(function(modules /* 所有可用的模块 */) {
  // ...
  window.webpackJsonp=function(chunkid,moreModules){
    for(const key of moreModules){
      modules[key]=moreModules[key]
    }
  }
})({
// ...
})

// a.chunk.sd2321sd.js
webpackJsonp("sd2321sd",{
  'more1':function(){...},
  'more2':function(){...},
  'more3':function(){...},
})

好了1、2点已经实现了,让我们再加上image和css的加载,其实也非常简单。

对于图片,我们require它的时候,我们希望返回的是一个合法的src 源就可以,例如base64,或者是一个url路径
对于css ,我们require它的时候,我们需要做的就是创建一个style,并且append 到 document head 就可以。

{
    image: function (module, exports, require) {
      module.exports = "/images/header.ada3q43.jpg";
    },
    css: function (module, exports, require) {
      var style = "h1[data-v-1111]{color:yellow;}"; // scoped
      const styleElem = document.createElement("style");
      styleElem.innerHTML = style;
      document.head.appendChild(styleElem);
    },
}

所以,我们现在可以知道了,webpack 的构建核心,是生成组织者:runtime 和各个module的组合:modules
我们来试试,手把手的构建一次,一个mini react hello world

const react = require("react");
const reactDom = require("react-dom");
const reactIcon= require("react-icon")
var image= react.createElement("img", { src: reactIcon }, null)
var component = react.createElement("h1",{},"Hello ", image ,". Welcome!");
reactDom.render(component, document.getElementById("app"));
@bigbossx bigbossx changed the title How webpack work? 关于 webpack Jan 14, 2023
@bigbossx bigbossx added the WIP work in progress label Jan 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
WIP work in progress
Projects
None yet
Development

No branches or pull requests

1 participant