Webpack基础原理及使用

什么是Webpack

Webpack 本质上是一个模块化打包工具,它通过“万物皆模块”这种设计思想,巧妙地实现了整个前端项目的模块化。在 Webpack 的理念中,前端项目中的任何资源都可以作为一个模块,任何模块都可以经过 Loader 机制的处理,最终再被打包到一起。

最初的时候,具体做法是将每一个功能及其相关状态数据各自放到不同的js文件中,一个script标签对应一个模块。


                ├── module-a.js
    ├── module-b.js
    └── index.html

缺点:

  • 模块直接在全局工作,大量模块成员污染全局作用域。

  • 不好管理模块与模块间的依赖关系。

  • 模块越多,容易产生命名冲突。

其他方式

使用立即执行函数

(function () {
  var name = 'module-a'

  function foo () {}

  window.moduleA = {
    foo: foo
  }
})()

模块化规范

在最早期以AMDCMD模块化规范这样的方式出现。再到后来的ES6的模块化(export、import),还有CommonJS规范。

Webpack工作过程简介

Webpack 官网首屏很清楚地描述了它的工作原理,如下图所示:

[图片上传失败...(image-2ae33a-1693882368824)]

项目中一般都会散落着各种各样的代码及资源文件,比如 JS、CSS、图片、字体等,这些文件在 Webpack 的思想中都属于当前项目中的一个模块。Webpack 可以通过打包,将它们最终聚集到一起。

具体来看打包的过程,Webpack 启动后,会根据我们的配置,找到项目中的某个指定文件(一般这个文件都会是一个 JS 文件)作为入口。然后顺着入口文件中的代码,根据代码中出现的 import(ES Modules)或者是 require(CommonJS)之类的语句,解析推断出来这个文件所依赖的资源模块,然后再分别去解析每个资源模块的依赖,周而复始,最后形成整个项目中所有用到的文件之间的依赖关系树,下面这个动画生动的演示了这个过程:

[图片上传失败...(image-28b3ec-1693882368824)]

Webpack 5 个核心概念

  • Entry:

入口起点(entry point) 指示 webpack 应该使用哪个模块,来作为构建其内部依赖图(dependency graph)的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。

  • output:

output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中。

  • loader:

webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块以供应用程序使用,以及被添加到依赖图中。

  • plugins: loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:代码压缩,生成 html ,打包优化,资源管理,注入环境变量等。

  • mode:

通过选择 development, productionnone 之中的一个,来设置 mode 参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为 production

示例:

// 首先初始化一个项目
npm init -y

// 在项目里面安装 webpack 以及 webpack-cli
npm i webpack webpack-cli

// 接下来创建 src 目录,下面创建 index.js 以及 data.json 这两个文件。

// index.js
import data from './data.json'
console.log(data);

function add(x, y) {
    return x + y;
}

console.log(add(1, 2));

// data.json
{
    "name" : "zhangran",
    "age" : 18
}

接下来使用如下命令进行打包:

webpack ./src/index.js -o ./build/built.js --mode=development

webpack ./src/index.js -o ./build/built.js --mode=production

在项目根目录下面创建 webpack.config.js,然后将 Webpack 配置中的入口文件路径指定为 main.css 的文件路径,让 Webpack 直接打包 CSS 资源文件,具体配置如下所示:

module.exports = {
  // 样式文件路径
  entry: './src/main.css',
  output: {
    filename: 'bundle.js'
  }
}

运行npx webpack,这时控制台会出现报错,需要适当的加载程序来处理此文件类型,目前没有配置加载程序来处理此文件。

You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.

加载 CSS 模块的 Loader,最常用到的是 css-loader。我们需要通过 npm 先去安装这个 Loader,然后在配置文件中添加对应的配置。

module.exports = {
    entry: './src/main.css',
    output: {
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.css$/, // 根据打包过程中所遇到文件路径匹配是否使用这个 loader
                use: 'css-loader' // 指定具体的 loader
            }
        ]
    }
}

[图片上传失败...(image-7cf211-1693882368823)]

添加完这个loader过后,打包过程就不会报错了。CSS 文件会交给 css-loader 处理过后再由 Webpack 打包,最后输出bundle.js。

我们在页面中使用这里输出的 bundle.js 文件,你会发现刚刚的这个 main.css 模块并没有工作。这里就需要用到另外一个loader

style-loader。运行以下命令,并添加配置:

npm i style-loader

module.exports = {
    mode:'development',
    entry: './src/main.css',
    output: {
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.css$/, //正则表达式, 根据打包过程中所遇到文件路径匹配是否使用这个 loader
                use: ['style-loader','css-loader'] // 指定具体的 loader   // 对同一个模块使用多个 loader,注意顺序
            }
        ]
    }
}

plugins

打包 html 资源,需要使用 html-webpack-plugin 这个插件。每次完整打包之前,自动清理 dist 目录需要使用clean-webpack-plugin。运行以下命令,并添加配置:

npm i html-webpack-plugin clean-webpack-plugin -D

//...
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

plugins : [
  // 自动为你生成一个 html 文件,并且引入你打包好的 js 文件
  new HtmlWebpackPlugin({
      title:'webpack test',
      // template:'./src/index.html',// 生成html模版文件
  }),
  // 自动清理dist目录
  new CleanWebpackPlugin()
],
//...

其实 Webpack 不仅是建议我们在 JavaScript 中引入 CSS,还会建议我们在代码中引入当前业务所需要的任意资源文件。因为真正需要这个资源的并不是整个应用,而是你此时正在编写的代码。这就是 Webpack 的设计哲学。(所有资源的加载都是由 JS 代码控制,后期也就只需要维护 JS 代码这一条线)

plugins最常见的应用场景:

  • 实现自动在打包前清除dist目录(上一次打包后的文件)。

  • 自动生成应用所需要的html文件。

  • 压缩Webpack打包完成后的输出文件。

  • ......

开发一个loader

一个可以加载 markdown 文件的加载器,以便可以在代码中直接导入 md 文件。我们都应该知道 markdown 一般是需要转换为 html 之后再呈现到页面上的,所以我希望导入 md 文件后,直接得到 markdown 转换后的 html 字符串,如下图所示:

[图片上传失败...(image-afa9-1693882368823)]

现在更目录下新建一个markdown-loader.js文件。

// webpack.config.jsmarkdown-loader.js

const marked = require('marked');

module.exports = source => {
    const html = marked(source);
    console.log(html)

    // 返回值就是最终被打包的内容
    return `module.exports = ${JSON.stringify(html)}`
}

每个 Webpack 的 Loader 都需要导出一个函数,这个函数就是我们这个 Loader 对资源的处理过程。它的输入就是加载到的资源文件内容,输出就是我们加工后的结果。我们通过 source 参数接收输入,通过返回值输出。

*函数返回的结果必须是一段标准的 JS 代码字符串。

// webpack.config.js

// ...
    rules: [
        {
            test: /\.css$/, //正则表达式, 根据打包过程中所遇到文件路径匹配是否使用这个 loader
            use: ['style-loader', 'css-loader'] // 指定具体的 loader
        },
        {
            test:/\.md/,
            use:'./markdown-loader' // 直接使用相对路径
        }
    ]
// ...

最后我们把导入到markdown文件显示到html文件中

// index.html
// ...
<div id="test"></div>

//index.js
import html from './test.md';
document.querySelector("#test").innerHTML = html;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容