乐趣区

关于webpack:手把手带你搭建一个简单的webpack脚手架一

这篇文章次要是从零开始,搭建一个基于 webpack 的反对 react + less + ts 的脚手架。次要是面向入门,心愿将整个搭建思路讲清楚来,帮忙老手搭建一个简略的 webpack 脚手架。曾经有相应教训的并不适宜。后续会退出单元测试,webpack 优化等内容,也作为集体学习的总结。本文的 github 地址。欢送 star,或是在 issues 提出相应的意见。git 上相应的 commit 也记录了整个搭建过程与正文。能够间接看 commit 学习。

注:本文 webpack 版本为 5 以上

webpack 是什么?

简而言之,webpack 是对于古代 js 应用程序的动态模块打包器。官网上的图片也扼要的阐明了相应的关系。在我的项目中,因为各类文件资源相互依赖(比方 html 引入了 image、字体资源等等)。webpack 能够通过剖析文件之间的依赖构建的依赖图,而后递归的通过依赖图将多种资源整合构建成最初的动态资源。但具体原理并不是本文的深刻点,这里大略有一个印象为主,让咱们接着下一步。

初始化我的项目

首先咱们须要创立一个我的项目,初始化 npm,并在本地装置 webpack 和 webpack-cli。(上面是在终端执行的命令行)。

mkdir webpack-demo
cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev

当初,咱们在根目录下创立以下目录文件和相应的内容。
我的项目目录:

webpack-demo
  |- package.json
+ |- index.html
+ |- /src
+   |- index.js

src/index.js

function component() {const element = document.createElement('div');

  // Lodash, currently included via a script, is required for this line to work
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Getting Started</title>
    <script src="https://unpkg.com/lodash@4.17.20"></script> 
  </head>
  <body>
    <script src="./src/index.js"></script>
  </body>
</html>

这是最原始的应用 lodash 库的形式,这时咱们将 index.html 在浏览器中运行能够看到 hello webpack 显示在页面上,这是因为 index.html 通过 script 标签引入了 lodash 库。所以 index.js 中的_.join 能力执行将 [‘Hello’, ‘webpack’] 拼成了 ’Hello webpack’。然而会带来几个问题:

  • lodash 全局存在,index.js 文件的执行依赖于 lodash.js。
  • 如果短少依赖项或蕴含谬误程序,那么 index.js 甚至无奈执行。
  • lodash 可能并没有应用,然而浏览器依旧会加载这个库。

那么 webpack 是如何对下面几种状况进行治理的呢?

创立捆绑包

首先让咱们先调整下我的项目构造。

webpack-demo
  |- package.json
+ |- /dist
+   |- index.html
- |- index.html
  |- /src
    |- index.js

本地装置 lodash 包

首先咱们须要先在我的项目根目录下通过 npm 下载相应的 lodash 包。

npm install --save lodash

下载后会呈现 node_modules 文件夹。这是 npm 下载在本地的库保留的文件夹,关上能够看到 lodash 库的源码。

而后更改上面两个文件。

src/index.js

+import _ from 'lodash';

 function component() {const element = document.createElement('div');

   element.innerHTML = _.join(['Hello', 'webpack'], ' ');

   return element;
 }

 document.body.appendChild(component());

这里的 lodash 是通过 import 进行导入的。咱们再将 index.html 中的 script 标签进行更改。
dist/index.html

 <!DOCTYPE html>
 <html>
   <head>
     <meta charset="utf-8" />
     <title>Getting Started</title>
-    <script src="https://unpkg.com/lodash@4.17.20"></script>
   </head>
   <body>
-    <script src="./src/index.js"></script>
+    <script src="main.js"></script>
   </body>
 </html>

而后在终端中执行 npx webpack,(npx webpack 会应用 webpack 默认的打包配置将目前我的项目进行打包)就能够对我的项目中的文件进行打包。

asset main.js 69.5 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1010 bytes 5 modules
cacheable modules 532 KiB
  ./src/index.js 297 bytes [built] 
  ./node_modules/lodash/lodash.js 531 KiB [built] 

从下面的输入中能够看出打包了两样货色 index.js 和 node_modules 中的 lodash。而这时我的项目文件夹会变成上面这样。

 webpack-demo
  |- package.json
+ |- package-lock.json
  |- /dist
+   |- main.js
+   |- main.js.LICENSE.txt
    |- index.html
  |- /src
    |- index.js

mian.js 就是咱们打包后的产物。dist/index.html 中的 <script src="main.js"></script> 将其导入。而 src/index.js 中执行了 import from 'lodash'。所以在 src/index.js 中,_.join 能够执行。那么如果咱们没有在 src/index.js 中写入这句 import from 'lodash' 的话,index.js 中的_.join 是无奈执行的。因为 webpack 通过对 import 语句的剖析,能够晓得以后脚本(src/index.js)是否须要引入 lodash 库,从而防止 lodash 在全局引入的净化。这也就解决了下面的那些问题。

好的,说到这,你想必曾经大抵理解了 webpack 打包与传统 script 标签导入的区别。那么咱们就进一步对整个工程进行配置化吧。

创立配置文件

webpack 能够应用相应的配置文件对 webpack 进行配置,也能够间接命令行运行配置,这里咱们应用配置文件。上面咱们创立一个配置文件(webpack.config.js)。

project

 webpack-demo
  |- package.json
  |- package-lock.json
  |- /dist
    |- main.js
    |- main.js.LICENSE.txt
    |- index.html
  |- /src
    |- index.js
+ |- webpack.config.js

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js', // 打包文件的入口,webpack 将从这个文件开始剖析整个我的项目的依赖构造
  output: {
    filename: 'main.js', // 输入的文件名称
    path: path.resolve(__dirname, 'dist'), // 输入的文件夹
  },
};

这里的两个字段 entry 和 output 是示意整个 webpack 打包过程中的终点与起点,entry 指定了打包的流程是从 src/index.js 开始,output 则指定了输入文件的一些属性。具体能够看下面代码中的正文。

当初咱们能够运行 npx webpack --config webpack.config.js 来对我的项目进行打包。

..[$] <((git)-[master]-)> npx webpack --config webpack.config.js
asset main.js 69.5 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1010 bytes 5 modules
cacheable modules 532 KiB
  ./src/index.js 297 bytes [built] 
  ./node_modules/lodash/lodash.js 531 KiB [built] 

npm scripts
如果咱们每次都要这样去输出这一大串的命令去执行的话,那么是有点吃力的,所以咱们能够对 package.json 中的命令行进行增加。简化相干的操作。
package.json

"scripts": {   
    "test": "echo \"Error: no test specified\"&& exit 1",
 +  "build": "webpack" 
 },

这时,咱们执行相应的 npm run build, 这样就能够代替 npx webpack --config webpack.config.js 进行 webpack 的打包。webpack.config.js 是 webpack 默认的打包文件,所以 npm run build 前面不指定的话,也是会默认应用这个文件的。

动态资源打包

从后面的步骤能够看到,咱们将我的项目下的源代码以及应用到了的 js 库打包起来,通过 index.html 引入。这样就能够搭建起来整个我的项目,然而 webpack 默认是只反对 js 和 json 文件的解析的。对于 png,css 这一类其余的资源是无奈进行解析的。那么如果咱们的我的项目中须要引入相应的动态资源的话,咱们该怎么办呢?webpack 对于这一类动态资源应用 loader 进行了解决。那么 loader 是什么?

Loader

Loader 能够让 webpack 解决除了 js 和 json 的其余类型的文件。并将他们退出到 webpack 的资源依赖图中。那让咱们来尝试为 webpack 减少解析 less 文件的性能吧。

less 文件解析

减少依赖,在我的项目目录下中运行上面的命令。

npm install --save-dev style-loader css-loader less-loader less

webpack.config.js

module.exports = {
  ...
  module: {    
        rules: [
 +          {+             test: /\.(css|less)$/i,
 +             use: [+                   {   loader: "style-loader"},
 +                   {loader: "css-loader"},
 +                  {loader: "less-loader"}, 
 +             ],      
 +         }, 
         ],
  },
  ...
};
  • style-loader:用来将 css 款式以 style 标签的款式注入到 index.html 的 header 中。
  • less-loader:解决 less 的 loader。

project

 webpack-demo
  |- package.json
  |- package-lock.json
  |- /dist
    |- main.js
    |- main.js.LICENSE.txt
    |- index.html
  |- /src
+   |- index.less
    |- index.js
  |- webpack.config.js

src/index.less

body {background-color: red;}

运行npm run build,能够发现打包胜利。关上浏览器预览成果。


上图阐明 less 文件被编译了。

然而有时候咱们须要解决一些 css 的前缀问题,用来做兼容。这时咱们能够应用 postcss 的 loader 来做这件事。

装置依赖

npm install --save--dev autoprefixer cssnano postcss postcss-loader

project

webpack-demo
  |- package.json
  |- package-lock.json
  |- /dist
    |- main.js
    |- main.js.LICENSE.txt
    |- index.html
  |- /src
    |- index.less
    |- index.js
  |- webpack.config.js
+ |- postcss.config.js
+ |- .browserslistrc

webpack.config.js

module.exports = {
  ...
  module: {    
        rules: [
           {test: /\.(css|less)$/i,
              use: [{   loader: "style-loader"},
                    {loader: "css-loader"},
+                   {loader: "postcss-loader"},
                    {loader: "less-loader"}, 
              ],      
          }, 
         ],
  },
  ...
};

postcss.config.js

module.exports = {  
        plugins: [    
            // 主动增加前缀 
            require("autoprefixer"), 

            // 优化合并 css    
            require("cssnano"),
        ],
};

.browserslistrc

> 0.25%
last 2 versions

这时咱们在 src/index.less 中减少一条 css 款式。

body {  
      background-color: red;
+     transition: background-color .4s;
}

这时咱们再执行 npm run build 打包,关上浏览器查看。

这示意前缀曾经胜利加上了。到这里 less 文件曾经配好了。

图片资源解决

webpack5 曾经内置了对于资源模块的加载,所以与 css 加载的形式有一些不同。

project

webpack-demo
  |- package.json
  |- package-lock.json
  |- /dist
    |- main.js
    |- main.js.LICENSE.txt
    |- index.html
  |- /src
+   |- icon.png
    |- index.less
    |- index.js
  |- webpack.config.js
+ |- postcss.config.js
+ |- .browserslistrc

webpack.config.js

const path = require("path");
module.exports = {  
    ...
    module: {
        rules: [
            {test: /\.(css|less)$/i,
                use: [{    loader: "style-loader",},
                         {loader: "css-loader",},
                         {loader: "postcss-loader",},
                         {loader: "less-loader",},
                    ],
            },
  +         {+               test: /\.(png|svg|jpg|jpeg|gif)$/i, 
  +               type: "asset/resource",      
  +         },
          ],
     },
};

src/index.js

import _ from "lodash";
import "./index.less";
import iconPng from "./icon.png";

function component() {const element = document.createElement("div");
   // Lodash, currently included via a script, is required for this line to work 
   element.innerHTML = _.join(["Hello", "webpack"], " ");  

   // Add the image to our existing div.  
+  const myIcon = new Image();  
+  myIcon.src = iconPng;  
+  element.appendChild(myIcon);  

    return element;
}

document.body.appendChild(component());

这时咱们再执行 npm run build 打包,关上浏览器查看。

图片失常加载。

以此类推,能够减少其余动态资源的解析。其余资源加载具体能够看官网文档。记得装置相应的 loader 的依赖。

webpack.config.js

const path = require("path");
module.exports = {  
    ...
    module: {
        rules: [
            {test: /\.(css|less)$/i,
                use: [{    loader: "style-loader",},
                         {loader: "css-loader",},
                         {loader: "postcss-loader",},
                         {loader: "less-loader",},
                    ],
            },
            {test: /\.(png|svg|jpg|jpeg|gif)$/i, 
                 type: "asset/resource",      
            },
+           {+               test: /\.(woff|woff2|eot|ttf|otf)$/i,
+               type: "asset/resource", 
+           },
+           {+                test: /\.(csv|tsv)$/i,
+                use: ["csv-loader"],
+            },
+            {
+                 test: /\.xml$/i,
+                 use: ["xml-loader"],
+             },          
        ],
     },
};

下一篇

退出移动版