7
最近由于学习需求,手撸了个简单的SPA框架并使用Webpack4做打包和预览调试,由于没有怎么系统学习过Webpack所以遇到坑挺多,索性直接开始从头学一波顺便记录下来.
写Webpack文章不写版本都是耍流氓,这篇文章基于当下最新的 webpack v4.22.0 以及 webpack-cli v3.1.2 编写.

本章以 环境搭建 -> 练习1 -> 理论学习 -> 练习2 的步骤进行:

  1. 跟随官方文档 Getting-Started, 由简单项目配置搭建开始;
  2. 完成后直接进入练习1--默认Webpack配置打包项目;
  3. 完成一波实战操作之后再回头了解 基本概念
  4. 完成概念学习之后再进入练习2--学习使用配置文件实现项目打包;

Tip:全过程将记录在Github仓库 webpack-stepbystep 中,边看文章边看commit学习食用效果更佳哟~

1. Init:简易Webpack项目搭建

想要学习Webpack的小伙伴大概都知道Webpack是用来打包的,嗯暂时知道这些就足够了,马上来开始第一次打包的体验吧~

开始实战肯定要创建工程的,使用下面的命令开始(需要 Node.js ):

mkdir webpack-stepbystep
cd webpack-stepbystep
npm init -y
npm i -D webpack webpack-cli
webpack -v
webpack-cli -v

上面的命令语句分别是:

  • 创建项目
  • 进入项目
  • 初始化 package.json
  • 在项目中安装 webpack & webpack-cli
  • 检查 webpack 版本
  • 检查 webpack-cli 版本

本文的环境是webpack v4.22.0 & webpack-cli v3.1.2, 最后两句版本检查如果运行失败的话,可以考虑使用全局方式安装 Webpack & Webpack-cli, 之前在Windows上开发的时候遇到过这个问题, 全局安装命令如下:

npm install -g webpack webpack-cli
webpack -v
webpack-cli -v

其他安装问题暂且按下不表, 可自行参考 Installation.

完成以上项目环境搭建之后,项目的文件结构大致如下所示:

webpack-stepbystep
    └─ node_modules
    └─ package-lock.json   
    └─ package.json

项目环境搭建至此全部完成, 以上环境搭建的项目提交为init(project): finish base enviroment setup, 马上进入实战环节.

2. 练习1:默认Webpack配置打包项目

2.1 从刀耕火种的写法开始

首先添加index.html & src/index.js, 项目的文件结构大致如下所示:

webpack-stepbystep
    └─ node_modules
    └─ src
        └─ index.js
    └─ index.html
    └─ package-lock.json   
    └─ package.json

编辑index.html, 其中用script引用了第三方工具库 lodash:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Started</title>
    <script src="https://unpkg.com/lodash@4.16.6"></script>
</head>
<body>
    <body>
        <script src="./src/index.js"></script>
    </body>
</body>
</html>

然后编辑 src/index.js , 代码中的 _ 即对lodash库的引用:

function component () {
    let element = document.createElement('div');
    element.innerHTML = _.join(['Hello', 'Webpack'], '');
    return element;
}
document.body.appendChild(component());

可以看出 index.html 中的两个 <script> 之间存在这隐式依赖的关系, 即 index.js 默认全局存在lodash. 这种刀耕火种时期的写法存在三个问题:

  1. 模块间的依赖关系不明显,工程变大难以查找依赖;
  2. 如果依赖丢失,将造成运行问题;
  3. 如果引用了依赖但是程序并无调用,下载无用库造成浪费并且影响速度

有错就要改,所以我们开始使用现代方案来对当前项目进行修改~

至此项目提交为 feat(project): add index.html & index.js with implicit dependencies .

2.2 现代化解决方案

现代的思想是用npm将库下载到本地,在js中显示声明依赖并调用,最后用Webpack完成打包,了解了之后就开始吧:

  • 第零步、我们先使用Webpack的默认配置打包项目,Webpack默认以./src/index.js为起点开始构建,获取依赖并完成打包到./dist/main.js. (文章第三节”学习:Webpack概念“将会介绍);
  • 第一步、将依赖安装到项目中. 之后 Webpack 会将依赖一起打包到main 防止依赖丢失造成的运行问题:

    npm i -S lodash
  • 第二步、在文件 index.js 顶部用import显式声明依赖. 方便依赖的查找的同时明确了项目所需的依赖:

    import _ from 'lodash';
    function component () {
        let element = document.createElement('div');
        element.innerHTML = _.join(['Hello', 'Webpack'], '');
        return element;
    }
    document.body.appendChild(component());
  • 第三步、执行打包. 打开终端在当前项目下运行 webpack ,运行成功之后发现当前项目目录多出了 dist 文件夹,项目的文件结构大致如下所示:

    webpack-stepbystep
        └─ dist
            └─ main.js
        └─ node_modules
        └─ src
            └─ index.js
        └─ index.html
        └─ package-lock.json   
        └─ package.json

完美~Webpack的打包操作现在已经完成了!只剩完成最后一步就可以完美运行程序了!

  • 第四步、按照 Webpack 的默认规则修改 index.html 中的引用. 先删除两个 <script> 标签,再添加对于Webpack生成 main.js 的引用;

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Started</title>
    </head>
    <body>
        <body>
            <script src="main.js"></script>
        </body>
    </body>
    </html>

由于 Webpack 的默认规则只能打包js,所以我们先用一下比较粗暴的手段,直接把index.html复制一份,放到打包完生成的dist文件夹下. 在浏览器运行该index.html.

WOW! 浏览器出现了 Hello Webpack的字样,运行成功!Webpack首战成功结束~接下来来了解一下Webpack的概念.

至此项目提交为 feat(project): combat:project bundle without configuration file .

3. 学习:Webpack概念

Concepts部分告诉了我们Webpack的定义、目的以及核心概念:

  • 定义:静态模块打包器
  • 目的:通过递归构建依赖关系图(dependency graph),将应用需要的模块打包,形成一个或者多个bundle
  • 核心概念:

    • 入口(entry): 告诉 Webpack 从那个模块(文件)开始构建dependency graph. Webpack将会以此为起点,找到所有的依赖并打包最终形成bundle.

      • Tip: 如果不在 webpack.config.js 中配置entry,Webpack将会默认使用路径 ./src/index.js 作为起点开始构建打包.
    • 输出(ouput): 告诉Webpack打包结果的创建位置&命名方式.

      • Tip: 如果不在 webpack.config.js 中配置output,Webpack将会默认在路径 ./dist 文件夹下创建打包结果main.js .
    • 加载器(loader): loader的作用是将所有类型的文件转换为可以被 dependency graph 直接应用的文件,也就是Webpack封面图--将所有依赖模块打包成静态资源

      • 使用方式: 每种类型的模块基本都有对应的loader负责其转换,但是Webpack并不具备loader. 使用一个新的loader,首先需要用npm或者yarn安装, 然后 webpack.config.jsmodule.rules 中进行手动配置,声明希望进行转换的文件类型及其对应的处理器loader(test、use).
      • 列表链接:loader列表
    • 插件(plugin): 执行范围更广的任务,例如:优化打包、压缩、注入新的环境变量等等.

      • 使用方式:使用一个新的plugin, 首先需要用npm或者yarn安装, 然后在webpack.config.js的顶部用require进行声明,接着在module.plugins中初始化并根据plugin的文档进行配置.
      • 列表链接:Plugin列表
    • 模式(Mode): 当前项目的打包模式,现有三种 nonedevelopmentproduction 模式可供选择. 现在暂时不管这个属性的配置.

4. 练习2:配置文件实战练习

Webpack提供了方便开箱即用的默认配置,但是想要充分发挥Webpack的能力,还是需要使用配置文件.

4.1. 使用配置文件复刻默认Webpack效果

如果 webpack.config.js 存在,则 webpack 命令将默认选择使用它,于是我们在项目根目录添加文件 webpack.config.js,项目的文件结构大致如下所示:

webpack-stepbystep
    └─ dist
        └─ main.js
    └─ node_modules
    └─ src
        └─ index.js
    └─ index.html
    └─ package-lock.json   
    └─ package.json
    └─ webpack.config.js

webpack.config.js 添加配置,使之实现默认Webpack配置的效果:

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
    }
};

删除dist文件夹,保存 webpack.config.js ,并打开终端在当前项目下运行 webpack ,运行成功之后发现当前项目目录再次生成了 dist 文件夹,里面有 main.js , 至此我们成功使用 webpack.config.js 成功复刻了默认Webpack配置的效果~

4.2. 使用配置文件实现项目自动化打包

当然这次实战的目标肯定不止如此,第一次实战中遗留着一个问题,就是Webpack的默认配置无法帮助我们将 index.html 一起打包到 dist 中,这导致项目无法全自动打包. 现在就来尝试借助 webpack.config.js 来解放Webpack的能力,实现项目的全自动化打包.

实现过程分为两个步骤:

  • 第一步、每次打包之前清除 dist 内容。已有打包内容容易对新打包内容造成影响,所以在这里使用一个叫做 clean-webpack-plugin 的插件,这个插件将帮助我们在每次打包之前清理 dist 文件夹的内容,插件的配置方法如下:

    1. 插件安装:首先通过 npm 再项目中安装插件:

      npm i -D clean-webpack-plugin
    2. 配置文件修改:在 webpack.config.js 文件开头用require引用插件,再在 plugins 数组中添加其插件的实现,完整配置文件代码如下所示:

      const path = require('path');
      const CleanWebpackPlugin = require('clean-webpack-plugin');
      
      module.exports = {
          entry: './src/index.js',
          output: {
              filename: 'main.js',
              path: path.resolve(__dirname, 'dist')
          },
          plugins: [
              new CleanWebpackPlugin(['dist'])
          ]
      };
      1. 测试: 完成配置文件插件添加之后,复制根目录下的 index.html 文件到 dist 中,再回到终端运行webpack , 执行成功后发现 dist 下只有一个刚被创建的 main.js , 即每次打包之前插件都会自动清理打包目标文件夹~
  • 第二步、在Webpack打包过程中,将根目录下的 index.html 文件复制到 dist 中. 这里需要用到一个叫做 html-webpack-plugin 的插件,这个插件功能很多,但是我们暂时需要它帮我们将根目录的 index.html 复制到 dist 中,配置方法如下:

    1. 插件安装:

      npm i -D html-webpack-plugin
    2. 配置文件修改:在 webpack.config.js 文件开头用require引用插件,再在 plugins 数组中添加其插件的实现,完整配置文件代码如下所示:

      const path = require('path');
      const CleanWebpackPlugin = require('clean-webpack-plugin');
      const HtmlWebpackPlugin = require('html-webpack-plugin');
      
      module.exports = {
          entry: './src/index.js',
          output: {
              filename: 'main.js',
              path: path.resolve(__dirname, 'dist')
          },
          plugins: [
              new CleanWebpackPlugin(['dist']),
              new HtmlWebpackPlugin({
                  inject: false,
                  template: 'index.html',
                  filename: 'index.html'
              })
          ]
      };
      1. 测试:完成配置文件插件添加之后,回到终端运行webpack , 执行完成后发现 dist 下已经出现了我们想要的两个文件 index.html & main.js,浏览器打开 index.html, 再次看到熟悉的 Hello Webpack!成功~至此第二次Webpack实战练习也成功结束了~这次我们完成了使用一句 webpack 就完成了项目打包,无需粗暴的复制黏贴,真正做到了全自动化打包项目!

至此项目提交为 feat(project): combat: project bundle with webpack.config.js .

5. 项目地址

To be continued...


Nodreame
155 声望32 粉丝

伪全栈|前端|前软粉