初识webpack4.0-基础原理

前言

之前都是使用,没有系统的完整的好好学习过一遍webpack的原理,趁现在工作有些闲空,整理下。加强下记忆

什么是webpack?

不想放webpack官网那张图,感觉都快看吐了。
算了还是妥协把,要不然不好说清楚.....
image
官网的哈,看能看出的来,那继续了~~

分为三个部分

左侧:

写项目的源代码,源文件
左侧有一个入口,最上面的.js
一个一个的方格可以理解成一个一个的模块,因为webpack是基于node的,所以可以用模块的概念来区分文件。
箭头的表示➡️一个模块可以依赖多个模块
箭头➡️表示他们之间的依赖关系
左侧会有很多,后缀的文件是浏览器无法识别的。例如:.sass .hbs .cjs
所以需要经过webpack 来构建一次打包

经过webpack的构建

右侧:

输出浏览器可以正确执行的文件,资源

我们还可以利用webpack来压缩 js 、压缩图片 。
所以webpack就是一个模块打包器

webpack安装

分为两种安装方式

  • 项目安装(推荐)
    有些项目可能很老,依赖的webpack的版本比较低。
    最新的是webpack4.X; webpack5.x还没有发布
  • 全局安装
    如果是全局安装,版本会固定化。如果是去修改来的版本会冲突,依赖冲突等。所以根据项目来安装webpack,会好些。

安装:
webpacl4.x之后,这两个必须要都安装,webpack和 webpack-cli;不建议分开装。

创建项目之后,现需要npm init一下,之后在安装。初始化一下。这个大家应该都知道。

npm install webpack webpack-cli -D

webpack启动

webpack4.0发布的时候,有说,支持零配置启动。结果发现,哈哈哈哈哈哈哈哈~~~没啥用。基本用不到项目中。

我们来看下零配置:
安装好webpack之后,我们来创建一个入口文件,index.js

零配置 :

默认入口:./src/index.js
如果没有src 下面的index.js 打包是不成功的。
默认出口:输出的目录是 ./dist,输出的资源名称:main.js

image
接下来,启动webpack,启动方式有两种。

第一种启动方式:

npx webpack

为啥用npx启动项目

npm5.2版本,就自带npx这个功能;
现在我们启动的整个项目webpack是局部安装的
如果全局没有安装webpack,全局执行 webpack 就会报错,command not found。它会去全局环境变量中去寻找。
通过npx 启动webpack,它会在当前项目下的node_modules/.bin 目录去找它的软连接,在.bin 目录下找到webpack,去启动它。

image

来看下,打包好里面都显示了啥?

  • 构建的哈希版本
Hash: 096bb4bcb72f81514554
  • 执行构建的webpack版本
Version: webpack 4.44.1
  • 执行构建的时长
Time: 217ms
  • 构造的内容是什么?

// 输出的资源叫main.js
// 这个资源是958 bytes
// Chunks 是为 0

Built at: 2020-08-25 14:45:08
  Asset       Size  Chunks             Chunk Names
main.js  958 bytes       0  [emitted]  main

// 这块表示 输出的main.js,是根据./src/index.js文件built而来的
Entrypoint main = main.js
[0] ./src/index.js 29 bytes {0} [built]
  • 警告内容

自己百度吧,好吗? 用我小学的英语水平大概就是:环境没有设置:就是生产环境和开发环境没设置。会走一个默认的值,默认值是production(生产模式);

生产模式下的代码是进行压缩的,现在可以看下,main.js
image
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

测试打包好的main.js;是否可以使用
在dist里面,手动创建一个index.html,然后手动引入main.js;
dist/index.html

<!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>Document</title>
</head>
<body>
  <script src="./main.js"></script>
</body>
</html>

第二种启动方式:

在package.json,的scripts中,添加启动命令

  "scripts": {
    "dev": "webpack"
  },

之后执行

npm run dev

效果和上面是一样的,就不进行在进行演示了。

当我们在scripts中去定定义了执行命令dev,执行webpack;是从本地的node_modules/.bin目录的软连接去找webpack

webpack配置文件,自定义配置文件

在根目录下创建,webpack.config.js
webpack.config.js 就是webpack的自定义配置文件
当我们执行 npx webpack
首先会去项目下去查找 是否有webpack.config.js,这个配置文件;如果没有会走默认配置;如果存在,就会按照webpack.config.js配置里面的内容去进行构建

webpack.config.js

webpack是基于node 的,所以可以直接导出模块
module.exports={
    entry(入口):(有三种类型)
    output(出口): {
        // 指定输入资源存放目录,位置
        // path 必须是绝对路径
        path:,
        //输出文件名
        filename:,
    }
    // 刚刚报的警告,就是这个值没有设置。
    mode: 构建模式
}

webpack.config.js

const path =require('path')
module.exports={
  entry:'./src/index.js',
  output:{
    path:path.resolve(__dirname,'./build'),
    filename:'main.js'
  },
  // 开发模式
  mode:'development'
}
npx webpack

image

目录新创建了一个build;main.js中的文件没有被压缩,开发模式下,文件不会被打包。

image

main.js 文件内容分析

main中是一个自执行的闭包函数
//行参 modules 所有的模块
(funcition(){modules})()
image

等下,我在创建个依赖js。为了方便看这个modules里面的内容。
image

image

modules是什么?

//modules 是一个对象,这个对象记录了,从入口模块出发,以及依赖模块的信息

image

来看下,在src/index.js中的内容

/***/ "./src/index.js":
/*!**********************!*\
  !*** ./src/index.js ***!
  \**********************/
/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _a_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./a.js */ \"./src/a.js\");\n\nconsole.log('hello webpack'+_a_js__WEBPACK_IMPORTED_MODULE_0__[\"str\"]);\n\n//# sourceURL=webpack:///./src/index.js?");

/***/ })
引入a.js的方式改为了__webpack_require_
通过webpack构建,对内容进行了一层处理,模块化语句也进行了一次处理
__webpack_require_ 在自执行函数中定义了这个方法的执行。

(先简单说明下,后面会写具体的文档)


继续webpack配置文件;比如我们在Vue cli工具创建的文件;所以我们可以自己去定义webpack配置文件的名称,可以不叫webpack.config.js;默认是走这个文件;
比如在根目录下新建一个,webpack.ohh.js;那如何让webpack走这个配置文件呢,
需要在package.js

// --config 用这个--config来进行匹配 
"scripts":{
    "dev": "webpack --config ./webpack.ohh.js"
}

image
执行npm run dev 进行打包

webpack核心概念

  • enrty:webpack执行构建的入口,默认是./src/index.js;
看官网那个图,就能看出来,需要一个js文件入口。当然这个文件入口也是可以修改的。
创建一个webpack.config.js,entry 就可以进行修改。
  • output: 配置资源输出的位置和名称,
打包好的文件放在什么位置,叫什么名字
  • mode:打包构建模式,有开发模式和生产模式两种。
development:开发模式,不压缩代码,有利于查找错误
productiont:生产模式,发布到线上的代码,代码会被压缩
  • chunk:代码片段,由入口模块文件与依赖模块的内容生成的。
  • module:模块,webpack基于nodeJs,有一切皆模块的概念
在刚刚我们打包的 a.js or index.js ;或者后面会去添加的 index.css,图片等,都可以成为模块

bundle: 打包输出到资源目录的文件,构建成功后的输出文件

顺一顺~~~~
bundle chunk module,三者的关系:

SPA 项目 一个单页面应用,只会有一个bundle 文件;
MPA 项目 多页面应用,就会有多页面的bundle文件;

比如index.js 和login.js

上面放了很多都是跑的SPA 单页面的应用;来看一个多页面MPA的。
首先是配置:

webpack.ohh.js

const path = require('path')
// 多入口
module.exports={
  entry:{
    index:'./src/index.js',
    login:'./src/login.js'
  },
  output:{
    path:path.resolve(__dirname, 'ohh'),
    filename:'[name].js'
  },
  mode:'development'
}

image

一个bundle 文件,对应一个chunk里面会有多个片段

MPA 多页面应用,才会存在多个chunks;
SPA 单页面应用,只有一个入口,一个chunk,(但是可能会有多个片段组成:

比如index.js中引入了a.js;那么chunk就有两个片段:一个是index、一个是a文件;);

**一个chunk对应一个entry
一个entry对应多个module**

  • loader:模块转换;webpack默认只支持js模块,json模块。

css模块,和图片模块都不支持。就需要用到loader,
比如:

src/index.css

body{
 background: pink;
} 

src/index.js
引入 css

// a.js
// export const str='这是ajs';
import {str} from './a.js'
import css from './index.css';
console.log('hello webpack'+str);

需要去配置loader
在配置文件,当然你也可以额写在webpack.config.js中。
创建一个module,写入加载规则
webpack.ohh.js

const path = require('path')
 // 多入口
module.exports={
 entry:{
   index:'./src/index.js',
   login:'./src/login.js'
 },
 output:{ path:path.resolve(__dirname, 'ohh'),
   filename:'[name].js'
 },
 mode:'development',
 module:{ // 模块
   rules:[ // 规则
     {
       test: /\.css$/,
       use: "css-loader"
     },
   ]
 }
}

进行安装 css-loader

npm install css-loader -D

之后来跑一下项目:

npm run dev

看一下打包结果
image
没有报错 也没有显示,因为:
css-loader 的作用非常的单一,只是让我们的webpack知道了,如何去处理css的语法,如何让css语法以字符串的方式,放到bundle文件里面去。
image

否则就会报错,接下来要做的是,将这段代码提取出来放到html中。

  npm install style-loader -D

style-loader 的作用:
将css提取出来,并且在html的头部,动态的生成style标签,将css放到里面去。
这时,还需要去修改下配置文件的module
webpack的配置文件修改;

module:{
  rules:[
      {
          test:/\.css$/,
          use:["style-loader", "css-loader"]
      }
  ]
 }
添加一个style-loader
loader的自行顺序,user:[];执行顺序是从后往前的,所以先要把css解析出来,以后再用style-loader,生成style标签,将css内容放进去。【从右到左】
  • 安装完了style-loader
  • 配置文件修改了css文件的匹配规则
  • 执行 npm run dev,查看页面加载情况
  • 在打包好的文件中,【自己 创建】创建一个index.html;这样可以看到效果
image
浏览器打开这个index.html
image
展示成功~~~~~!耶✌️
  • 结论:
    css-loader和style-loader需要配合来使用
  • 为什么css-loader功能单一,为什么要配合style-loader 才生效?

因为 自定义loader规定,一个loader只做一件事情。
style-loader的功能也很单一,把样式放在一个动态生成的style标签里面。所以不会在本地打包的html文件中显示出来,是通过js动态生成的。所以引入js就可以。
如果像将css处理成单独的文件,而不是在页面创建一个style标签的形式放在html里面。那就不能用style-loader;
index.less的文件,我们就有需要去加新的匹配规则,["style-loader","css-loader","less-loader"]

  • plugin:webpack 的一个功能扩展

举例: 像我们刚刚手动去创建的index.html
如果我们想要看到效果就需要,在打包我的文件夹中去手动创建index.html;非常的繁琐,那么如何解决呢?这个时候利用plugin;相当于webpack 的一个功能扩展。【官网中-右上角导航就有plugin,找一个合适的进行使用】
接下来,以如何自动创建index.html 来进行开展plugin的使用讨论

先安装:

 npm install html-webpack-plugin -D

image

  • 配置webpack默认项:

webpack.config.js

const path =require('path')
// 这里导入html-webpack-plugin
const htmlWebpackPlugin = require('html-webpack-plugin')
// 单入口
module.exports={
    entry:'./src/index.js',
    output:{
        path:path.resolve(__dirname,'./build'),
        filename:'main.js'
    },
    // 开发模式
    mode:'development',
    module:{
        rules:[
            {
                test:/.css$/,
                use:['style-loader','css-loader']
            }
        ]
    },
    plugins:[
        new htmlWebpackPlugin({ // plugin的使用,先new一下
            template:'./src/index.html', // 模板文件
            filename:'index.html' //倒出的文件名
        })
    ]
}

因为是在默认文件配置,所以跑起来,需要执行

 npx webpack

效果如下:
image
这样就打包成功了,那么直接用浏览器打开index.html
就可以看到效果了。并不在截图,因为和上面那个图片展示是一样的。就换成了自动生成html而已,仅此而已。
继续~~~~~(为什么要总结原理,我越写饿了,难过)

为了保证每次创建出来的build,打包文件都是全新的,而且不存在冗余的文件,比如说,当我们修改了一下 plugins中的
new htmlWebpackPlugin中的打包目录地址的配置:
filename:'html/ohh.html'
那么上次打包在根目录下的html并不会删除,就冗余了呗。
我们就需要用到plugin来进行配置
先安装:

npm install clean-webpack-plugin -D

使用,都是一样的

const {CleanWebpackPlugin} = require('clean-webpack-plugin')
// 在pulugins中new一
plugins:[
   new htmlWebpackPlugin({ // plugin的使用,先new一下
   template:'./src/index.html', // 模板文件
   filename:'index.html' //倒出的文件名
   }),
    new CleanWebpackPlugin()
]
  • 引入css文件而不是写在style标签里面,把样式抽离成独立的文件

首先安装plugin

npm install mini-css-extract-plugin -D

修改webpack的配置文件

  1. 引入plugin
plugins:[
   new miniCssExtractPlugin({
       filename:'css/index.css'
   })
]
  1. 修改css文件的模块匹配规则和渲染方式
module:{
   rules:[
       {
           test:/.css$/,
           use:[miniCssExtractPlugin.loader,'css-loader']
       }
   ]
},

image

基本原理就差不多顺明白了。总结下


总结

webpack.config.js: webpack配置文件

基本概念

  • entry:webpack执行构建任务的入口文件
  • output:执行构建后,资源配置的输出位置和名称
  • module: 模块
  • chunk:入口文件和依赖模块组合,经过webpack构建成生的一段代码片段
  • bundle: webpack构建完成够后输出的文件
  • loader: 模块转化,让webpack可以支持转化更多的模块类型
  • plugin:插件,让webpack功能更强大
  • modle: 打包构建模式,开发模式or生产模式

核心配置

  • enrty:String|[]|{}
[] : 单页面应用
{}: 可以SPA or MPA。多入口对应多出口文件
  • output:{path:,filename:“”}
path:必须是绝对路径
filename 可以使用占位符 [name] [hash]等
  • mode:String
参数:“production” “development” “node”
  • module :{}
{rules:[]}
  • plugins : []
    • *

webpack的学习,其实就是各种plugin和module的使用,用多了就写的顺了,所以主要的还是基础概念要清楚,所以才单独拿出来进行一个梳理,鄙人见解哈。

阅读 245

推荐阅读