你看不懂 webpack,是由于不知道js的进化史

若是你如今还不懂 webpack,我相信你必定和我最开始同样,对官网的这张图一脸懵逼,就算如今,我仍是以为这张图对新手起了很大的误导做用。
这究竟是是想表达什么意思?


咱们今天就从js发展的角度来讲明,到底什么是 webpack。


JS的设计初衷

——————

js 早期设计的目的是辅助页面交互和丰富页面样式,这使得 js 能进行 dom 操做。 好比下面这样。

  
  
  
  
<html>
    <body></body>
    <script>
        const ele = document.createElement('DIV');
        ele.style.background = 'red';
        ele.style.width = '100px';
        ele.style.height = '100px';
        document.body.append(ele);
    </script>
</html>

上面的 js 代码至关于下面的 html 代码。

  
  
  
  
<html>
    <body>
        <div style="background:red;width:100px;height:100px"></div>
    </body>
</html>

虽然使用 js 的写法很麻烦,可是至少表明了 js 有这方面的能力,他能在不依靠 html 和 css 的状况下,独立进行页面的显示。

IE最后的礼物

——————

IE 虽然一直让人诟病,可是有他留下的 xmlHttpRequest 确实是一大宝贝,他能在页面不刷新的状况下,请求和获取后端数据。 这个能力再配合js对于dom操做的能力,就能完成一些骚操做。 好比在页面不刷新的状况下,加载一篇新的文章、发布评论功能等等。 这也是最先单页面应用的雏形。

你可能不知道早期在论坛进行一次简单的评论,要通过2次页面的跳转

Node让js突破能力的界限

———————————

node 他既不是开发语言,也不是什么框架,他是一个开发环境。 咱们原来的js是运行在浏览器,这注定他有不少事情作不了,最基本的就是,他不能在浏览器对你本地文件进行增删改。 而node他是运行在本地的,他没有在浏览器端那些限制,他有极高的权限,其中同样就是能够对本地文件进行增删改。
也正是这一特征,他让预处理语言获得了极大发展。 咱们能够本身制定一套语法,而后经过转换器(loader),编译成html能够理解的语言。 目前html主要就认识2种文件,css和js。


模块化的进化

——————

其实前端模块化一直都在,咱们将一个个js写好,而后在html里面一个个引用,这就是最先的模块化。 可是这产生了一个问题,这些引入关系都是写在html里面的,两个js文件之间要进行交互,也只能经过全局变量赋值的形式。

那有没有办法在js里组织这些引用关系呢?

答案是能够的,目前比较主流的方式是 Node的common.js和ES6的ESModule两种方式,下面使用ESModule来改变一下以前的引用方式。

以前咱们是这样引用的:
  
  
  
  
<html>
    <body>
        <script src="js/jquery.js"></script>
        <script src="js/util.js"></script>
        <script src="js/index.js"></script>z
    </body>
</html>

如今咱们能够这样作:
  
  
  
  
<html>
    <body>
        <script src="js/index.js"></script>z
    </body>
</html>

  
  
  
  
/* 这是index.js 的内容 */
import $ from 'jquery.js';
import util from 'util.js';

$('div').remove();

至此,咱们已经了解了使用webpack的四个先决条件了。

主角登场

————

如何构建一个单页面应用? 下面咱们从一个需求入手,来引出为啥须要webpack。

第一步,咱们须要一个html和一个js:
  
  
  
  
# 目录结构
index.html
index.js

  
  
  
  
<html>
    <body>
        <script src="index.js"></script>
    </body>
</html>

function showIndex(){

    document.body.innerText = '这是首页';
}
function showList(){
    document.body.innerText = '这是列表页';
}
function showArticle(){
    document.body.innerText = '这是内容页';
}

const arr = [
    ['首页',showIndex],
    ['列表页',showList],
    ['内容页',showArticle],
]

arr.forEach((item)=>{
    const ele = document.createElement('DIV');
    ele.innerText = item[0];
    ele.onclick = item[1];
    document.body.append(ele);
}) 复制代码


代码逻辑很简单,就是在页面渲染一些内容,而后点击会跳转到不一样的页。 可是若是全部内容都写在index.js里,代码会变得很巨大,后期也很很差维护, 因此咱们对index.js进行功能拆分,而后使用引用的方式,将他们关联起来。

对功能进行拆分以后项目的样子:
  
  
  
  
# 目录结构
pages
  |__ home.js
  |__ list.js
  |__ article.js
index.js
index.html

import { showIndex } from 'js/home.js';

import { showList } from 'js/list.js';
import { showArticle } from 'js/article.js';

const arr = [
    ['首页',showIndex],
    ['列表页',showList],
    ['内容页',showArticle],
]

arr.forEach((item)=>{
    const ele = document.createElement('DIV');
    ele.innerText = item[0];
    ele.onclick = item[1];
    document.body.append(ele);
}) 复制代码


  
  
  
  
function showIndex(){
    document.body.innerText = '这是首页';
}

export showIndex;

可是有个问题,上面的代码在老版本的浏览器是没法运行的,由于老版本浏览器,不支持ES6模块, 因此咱们须要使用node对项目源代码进行分析打包,造成新的浏览器能够运行的代码,就变成了新的目录结构。

  
  
  
  
# 目录结构
dist
  |__ index.js
  |__ index.html
src
  |__ pages
  |     |__ home.js
  |     |__ list.js
  |     |__ article.js
  |__ index.js
  |__ index.html

分析打包的过程就是,咱们须要写一个脚本,node执行这个脚本,脚本内容是去打开index.js文件,而后对代码进行解读,当遇到依赖引入的地方时,而后把代码复制进来,看下面这个动图就能够一清二楚。


固然咱们不须要本身写这个脚本,由于咱们有 webpack, webpack的第一个功能,就是作上面的事情,从入口文件开始分析,对依赖进行合并,而后打包输出。

而webpack的第二个功能,就是他能够处理你引入任何格式的文件,注意,是任何格式。 前面介绍过,在前端有不少预处理语言,他们能极大方便咱们的开发,可是预处理语言须要进行编译,才能成为可以使用的语言。 而webpack,就能帮咱们进行编译。
webpack 当处理到不认识的文件格式时,会把他转化为字符串,而后使用loader对他进行转化,转化成js认识的格式。

以上面的项目为例子,咱们将被引用的几个脚本文件改成了ts的文件形式。

  
  
  
  
# 目录结构
dist
  |__ index.js
  |__ index.html
src
  |__ pages
  | |__ home.ts
  | |__ list.ts
  | |__ article.ts
  |__ index.js
  |__ index.html

js默认是不认识ts文件里的内容的,即便他们很像,因此webpack在解析ts文件时,要先作一个事情,就是先把ts转为js格式,而后在对转化后的js进行引入。


loader是能够拓展的,因此只要你有被引入文件的loader,理论上你能够引入任何文件格式。

webpack的第三个功能,就是插件。 插件就是webpack在执行分析打包任务时,你能够作一些额外的操做。 好比说,在引入css后对css进行自动添加适配前缀、对项目总体代码进行压缩等等,都是插件的功能体现。 由于说到底,代码就是字符串,webpack能获取到整个项目,包括依赖文件的代码(字符串),而后他在这个字符串作一些操做,也很好理解。


这就是webpack的三个主要功能,他的可拓展性,让他极具创造力,现在基本已经成为了全部web应用的基建部分,正所谓时势造英雄,他生在了前端最须要他的年代,我相信他构建的打包模式,不会是咱们前端的最终形态,只要js还在进步,还在变化,就会有新的模式出现。