这篇文章次要是从零开始,搭建一个基于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-democd webpack-demonpm init -ynpm 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 assetruntime modules 1010 bytes 5 modulescacheable modules 532 KiB  ./src/index.js 297 bytes [built] [code generated]  ./node_modules/lodash/lodash.js 531 KiB [built] [code generated]

从下面的输入中能够看出打包了两样货色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.jsasset main.js 69.5 KiB [emitted] [minimized] (name: main) 1 related assetruntime modules 1010 bytes 5 modulescacheable modules 532 KiB  ./src/index.js 297 bytes [built] [code generated]  ./node_modules/lodash/lodash.js 531 KiB [built] [code generated]

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"],+             },                  ],     },};

下一篇