模块化开发 webpack

news/2024/11/7 12:30:19/

模块化开发 & webpack

  • 1、模块化开发 & webpack
    • 1.1 webpack 执行过程
      • 1.1.1 初始化
      • 1.1.2 编译
      • 1.1.3 输出
    • 2.1 webpack 基础配置
      • 2.1.1 Entry
        • 2.1.1.1 context
        • 2.1.1.2 Entry类型
      • 2.1.2 output
        • 2.1.2.1 filename
        • 2.1.2.2 publicPath
        • 2.1.2.3 path
        • 2.1.2.4 libraryTarget 和 library
      • 2.1.3 module
        • 2.1.3.1 loader
        • 2.1.4 Resolve
        • 2.1.5 总结
    • 2.2 编写loader
      • 2.2.1 loader基础
      • 2.2.2 loader进阶
      • 2.2.3 加载本地Loader
      • 2.2.4 实战
    • 2.3 编写plugin
      • 2.3.1 Compiler 和 Compilation
      • 2.3.2 事件流

为什么要将文件进行打包?
1、转换文件 兼容性
2、对众多资源处理 css font image
3、产物优化 代码压缩 代码丑化 源码安全性 减少文件体积

webpack_5">1、模块化开发 & webpack

问题:
1、从0-1使用 webpack 进行搭建 vue react
2、对 webpack 执行过程
3、常用的 plugins 自定义自己的插件 事件机制 tapable 发布订阅模式 事件注册 触发等
4、常用的 loaders 自定义的loader 内容 原理 babel-loader es6+es5 ast
5、优化:
-体积:采取xxx、xxx
-构建速度:采取

webpack__14">1.1 webpack 执行过程

在这里插入图片描述

1.1.1 初始化

初始化参数,后续参数合并options
1、配置项

  • entry 入口 第一步从entry 开始
  • module 不同文件解析内容
  • loader 模块转换器 babel-loader ts-loader等
  • plugin 扩展插件 构建过程 广播事件 插件监听这些事件 在特定时机做对应事情

2、实例化 compiler new Compiler(options)
-负责文件监听和启动编译 全局唯一

3、加载插件 插件的apply 对事件进行监听 compiler

1.1.2 编译

run 启动一次新的编译

compilation 模块的资源 编译生成的资源 变化的文件

1.1.3 输出

输出打包后的文件

emit

done

webpack__41">2.1 webpack 基础配置

2.1.1 Entry

entry是配置模块的入口,可抽象成输入,Webpack 执行构建的第一步将从入口开始搜寻及递归解析出所有入口依赖的模块。

2.1.1.1 context

Webpack 在寻找相对路径的文件时会以 context 为根目录,context 默认为执行启动 Webpack 时所在的当前工作目录。 如果想改变 context 的默认配置,则可以在配置文件里这样设置它:

module.exports = {context: path.resolve(__dirname, 'app')
}
2.1.1.2 Entry类型
  • string ‘./app/entry’ 入口模块的文件路径,可以是相对路径。
  • array [‘./app/entry1’, ‘./app/entry2’] 入口模块的文件路径,可以是相对路径。
  • object { a: ‘./app/entry-a’, b: [‘./app/entry-b1’, ‘./app/entry-b2’]} 配置多个入口,每个入口生成一个 Chunk

如果是 array 类型,则搭配 output.library 配置项使用时,只有数组里的最后一个入口文件的模块会被导出。

2.1.2 output

output 配置如何输出最终想要的代码。output 是一个 object,里面包含一系列配置项:

2.1.2.1 filename

配置输出文件的名称,为string 类型。如果只有一个输出文件,则可以把它写成静态不变的:

 filename: 'bundle.js'

但是在有多个 Chunk 要输出时,就需要借助模版和变量了。前面说到 Webpack 会为每个 Chunk取一个名称,可以根据 Chunk 的名称来区分输出的文件名:

filename: '[name].js'

代码里的[name] 代表用内置的 name 变量去替换[name],这时你可以把它看作一个字符串模块函数, 每个要输出的 Chunk 都会通过这个函数去拼接出输出的文件名称。

内置变量除了 name 还可以包括:

  • id chunk 唯一id
  • name: chunk 名称
  • hash Chunk 的唯一标识的 Hash 值
  • chunkhash Chunk 内容的 Hash 值

输出 => filename:‘[name][hash].js’

2.1.2.2 publicPath

静态资源URL前缀 形成完整 url

filename:'[name]_[chunkhash:8].js'
publicPath: 'https://cdn.example.com/assets/'
2.1.2.3 path

output.path 配置输出文件存放在本地的目录,必须是 string 类型的绝对路径。

 path: path.resolve(__dirname, 'dist_[hash]')

output.path 和 output.publicPath 都支持字符串模版,内置变量只有一个:hash 代表一次编译操作的 Hash 值。

2.1.2.4 libraryTarget 和 library
  • libraryTarget 何种方式导出当前库
  • library 导出库的名称 antd

2.1.3 module

module 配置如何处理模块。

2.1.3.1 loader

loader 何种方式处理模块
文件类型 针对不同的文件类型 如何处理
比如js用babel-loader。ts、vue、md、css、less对应使用不同loader等等,也可以使用自定义loader

示例:

module: {rules: [{// 命中 JavaScript 文件test: /\.js$/,// 用 babel-loader 转换 JavaScript 文件// ?cacheDirectory 表示传给 babel-loader 的参数,用于缓存 babel 编译结果加快重新编译速度use: ['babel-loader?cacheDirectory'],// 只命中src目录里的js文件,加快 Webpack 搜索速度include: path.resolve(__dirname, 'src')},{// 命中 SCSS 文件test: /\.scss$/,// 使用一组 Loader 去处理 SCSS 文件。// 处理顺序为从后到前,即先交给 sass-loader 处理,再把结果交给 css-loader 最后再给 style-loader。use: ['style-loader', 'css-loader', 'sass-loader'],// 排除 node_modules 目录下的文件exclude: path.resolve(__dirname, 'node_modules'),},{// 对非文本文件采用 file-loader 加载test: /\.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,use: ['file-loader'],},]
}
2.1.4 Resolve

resolve 入口模块如何找出所有依赖的模块

  • alias 别名配置 :通过别名来把原导入路径映射成一个新的导入路径
  // Webpack alias 配置
resolve:{alias:{components: './src/components/'}
}

当你通过 import Button from 'components/button' 导入时,实际上被 alias 等价替换成了 import Button from './src/components/button'

以上 alias 配置的含义是把导入语句里的 components 关键字替换成 ./src/components/。

  • extensions 在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试访问文件是否存在。
 extensions: ['.js', '.json']

当遇到 require(‘./data’) ,data省略了后缀名,先查找有没有data.js,再找data.json,都没有就会报错

2.1.5 总结

Webpack 内置了很多功能。 你不必都记住它们,只需要大概明白 Webpack 原理和核心概念去判断选项大致属于哪个大模块下,再去查详细的使用文档。
通常你可用如下经验去判断如何配置 Webpack:

  • 想让源文件加入到构建流程中去被 Webpack 控制,配置 entry;
  • 想自定义输出文件的位置和名称,配置 output;
  • 想自定义寻找依赖模块时的策略,配置 resolve;
  • 想自定义解析和转换文件的策略,配置 module,通常是配置 module.rules 里的 Loader;
  • 其它的大部分需求可能要通过 Plugin 去实现,配置 plugin;

2.2 编写loader

Loader 就像是一个翻译员,能把源文件经过转化后输出新的结果,并且一个文件还可以链式的经过多个翻译员翻译。

以处理 SCSS 文件为例:

  1. SCSS 源代码会先交给 sass-loaderSCSS 转换成 CSS
  2. sass-loader 输出的 CSS 交给 css-loader处理,找出 CSS 中依赖的资源、压缩 CSS 等;
  3. css-loader 输出的 CSS 交给 style-loader 处理,转换成通过脚本加载的 JavaScript 代码;

可以看出以上的处理过程需要有顺序的链式执行,先 sass-loadercss-loaderstyle-loader。 以上处理的 Webpack 相关配置如下:

module.exports = {module: {rules: [{// 增加对 SCSS 文件的支持test: /\.scss$/,// SCSS 文件的处理顺序为先 sass-loader 再 css-loader 再 style-loaderuse: ['style-loader',{loader:'css-loader',// 给 css-loader 传入配置项options:{minimize:true, }},'sass-loader'],},]},
};

一个 Loader 的职责是单一的,只需要完成一种转换。 如果一个源文件需要经历多步转换才能正常使用,就通过多个 Loader 去转换。

2.2.1 loader基础

一个 Loader 其实就是一个 Node.js 模块,这个模块需要导出一个函数。
这个导出的函数的工作就是获得处理前的原内容,对原内容执行处理后,返回处理后的内容

一个最简单的 Loader 的源码如下:

module.exports = function(source) {// source 为 compiler 传递给 Loader 的一个文件的原内容// 该函数需要返回处理后的内容,这里简单起见,直接把原内容返回了,相当于该 Loader 没有做任何转换return source;
};

由于 Loader 运行在 Node.js 中,你可以调用任何 Node.js 自带的 API,或者安装第三方模块进行调用:

const sass = require('node-sass');
module.exports = function(source) {return sass(source);
};

2.2.2 loader进阶

以上只是个最简单的 Loader,Webpack 还提供一些 API 供 Loader 调用
1、获得 Loader 的 options
在最上面处理 SCSS 文件的 Webpack 配置中,给 css-loader 传了 options 参数,以控制 css-loader。 如何在自己编写的 Loader 中获取到用户传入的 options 呢?需要这样做:

const loaderUtils = require('loader-utils');
module.exports = function(source) {// 获取到用户给当前 Loader 传入的 optionsconst options = loaderUtils.getOptions(this);return source;
};

2、返回其他结果
上面的 Loader 都只是返回了原内容转换后的内容,但有些场景下还需要返回除了内容之外的东西。
例如以用 babel-loader 转换 ES6 代码为例,它还需要输出转换后的 ES5 代码对应的 Source Map,以方便调试源码。 为了把 Source Map 也一起随着 ES5 代码返回给 Webpack,可以这样写:

module.exports = function(source) {// 通过 this.callback 告诉 Webpack 返回的结果this.callback(null, source, sourceMaps);// 当你使用 this.callback 返回内容时,该 Loader 必须返回 undefined,// 以让 Webpack 知道该 Loader 返回的结果在 this.callback 中,而不是 return 中 return;
};

3、同步与异步
有些场景下转换的步骤只能是异步完成
在转换步骤是异步时,你可以这样:

module.exports = function(source) {// 告诉 Webpack 本次转换是异步的,Loader 会在 callback 中回调结果var callback = this.async();someAsyncOperation(source, function(err, result, sourceMaps, ast) {// 通过 callback 返回异步执行后的结果callback(err, result, sourceMaps, ast);});
};

4、处理二进制数据

module.exports = function(source) {// 在 exports.raw === true 时,Webpack 传给 Loader 的 source 是 Buffer 类型的source instanceof Buffer === true;// Loader 返回的类型也可以是 Buffer 类型的// 在 exports.raw !== true 时,Loader 也可以返回 Buffer 类型的结果return source;
};
// 通过 exports.raw 属性告诉 Webpack 该 Loader 是否需要二进制数据 
module.exports.raw = true;

5、缓存加速
如果你想让 Webpack 不缓存该 Loader 的处理结果,可以这样:

module.exports = function(source) {// 关闭该 Loader 的缓存功能this.cacheable(false);return source;
};

6、其他Loader API
Webpack 官网

2.2.3 加载本地Loader

两种方式:
1、 npm link:把Loader链接到node_moduels 下
2、配置ResolveLoader // 去哪些目录下寻找 Loader,有先后顺序之分

module.exports = {resolveLoader:{// 去哪些目录下寻找 Loader,有先后顺序之分modules: ['node_modules','./loaders/'],}
}

2.2.4 实战

创建名为comment-require-loader
自定义Loader作用是把 @require '../style/index.css'转为require('../style/index.css');

该 Loader 的使用方法如下:

module.exports = {module: {rules: [{test: /\.js$/,use: ['comment-require-loader'],// 针对采用了 fis3 CSS 导入语法的 JavaScript 文件通过 comment-require-loader 去转换 include: [path.resolve(__dirname, 'node_modules/imui')]}]}
};

具体实现时:

function replace(source) {// 使用正则把 // @require '../style/index.css' 转换成 require('../style/index.css');  return source.replace(/(\/\/ *@require) +(('|").+('|")).*/, 'require($2);');
}module.exports = function (content) {return replace(content);
};

2.3 编写plugin

一个最基础的 Plugin 的代码是这样的:

class BasicPlugin{// 在构造函数中获取用户给该插件传入的配置constructor(options){}// Webpack 会调用 BasicPlugin 实例的 apply 方法给插件实例传入 compiler 对象apply(compiler){compiler.plugin('compilation',function(compilation) {})}
}// 导出 Plugin
module.exports = BasicPlugin;

在使用这个 Plugin 时,相关配置代码如下:

const BasicPlugin = require('./BasicPlugin.js');
module.export = {plugins:[new BasicPlugin(options),]
}

2.3.1 Compiler 和 Compilation

在开发 Plugin 时最常用的两个对象就是 CompilerCompilation,它们是 PluginWebpack 之间的桥梁。 CompilerCompilation 的含义如下:

  • Compiler 对象包含了 Webpack 环境所有的的配置信息,包含 optionsloadersplugins 这些信息,这个对象在 Webpack 启动时候被实例化,它是全局唯一的,可以简单地把它理解为 Webpack 实例;
  • Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。当 Webpack 以开发模式运行时,每当检测到一个文件变化,一次新的 Compilation 将被创建。Compilation 对象也提供了很多事件回调供插件做扩展。通过 Compilation 也能读取到 Compiler 对象;
    Compiler 和 Compilation 的区别在于:Compiler 代表了整个 Webpack 从启动到关闭的生命周期,而 Compilation 只是代表了一次新的编译

2.3.2 事件流

Webpack 就像一条生产线,要经过一系列处理流程后才能将源文件转换成输出结果。 这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。 插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。
Webpack 通过 Tapable 来组织这条复杂的生产线。 Webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作。 Webpack 的事件流机制保证了插件的有序性,使得整个系统扩展性很好。

在开发插件时,还需要注意以下几点:

  • 只要能拿到 Compiler 或 Compilation 对象,就能广播出新的事件,所以在新开发的插件中也能广播出事件,给其它插件监听使用。
  • 传给每个插件的 Compiler 和 Compilation 对象都是同一个引用。也就是说在一个插件中修改了 Compiler 或 Compilation 对象上的属性,会影响到后面的插件。
  • 有些事件是异步的,这些异步的事件会附带两个参数,第二个参数为回调函数,在插件处理完任务时需要调用回调函数通知 Webpack,才会进入下一处理流程。例如:
 compiler.plugin('emit',function(compilation, callback) {// 支持处理逻辑// 处理完毕后执行 callback 以通知 Webpack // 如果不执行 callback,运行流程将会一直卡在这不往下执行 callback();});

http://www.ppmy.cn/news/1545055.html

相关文章

Pytorch学习--神经网络--现有网络模型的使用及修改

一、VGG16 weights (Optional[VGG16_Weights]): 这个参数是可选的,指的是预训练的权重。用户可以选择使用不同的预训练权重,具体可参见 VGG16_Weights 的详细说明。默认情况下,如果不提供此参数,模型将不会使用任何预训练权重。 p…

Java学习路线:Maven(二)scope、optional和exclusions

目录 scope optional exclusions 我们知道,一般来说一个依赖由三个基本的属性作为定位坐标,即groupId、artifactId和version 除了这三个基本属性以外,依赖还可以添加其他的属性,例如scope、optional和exclusions等 这篇文章将…

轻量级Nacos来了!占用资源极低,性能炸裂!

Nacos作为一款非常流行的微服务注册中心,我们在构建微服务项目时往往会使用到它。最近发现一款轻量级的Nacos项目r-nacos,占用内存极低,性能也很强大,分享给大家。本文就以我的mall-swarm微服务电商实战项目为例,来聊聊…

Docker篇(registry私服)

目录 一、私有仓库搭建与配置 1. 拉取私有仓库镜像(此步省略) 2. 启动私有仓库容器 3. 打开浏览器访问 4. 修改daemon.json 5. 重启docker 服务 二、镜像上传至私有仓库 1. 标记此镜像为私有仓库的镜像 2. 再次启动私服容器 3. 上传标记的镜像 …

必应国内广告开户代理商,推广怎么收费?

2024年,必应国内广告凭借其独特的优势,已经成为众多企业拓展市场、提升品牌影响力的重要渠道。 一、必应国内广告费用说明 1、必应开户费用:通常情况下,必应国内广告推广需要媒体预充值5000元,开户服务费用为 2000 元…

微信小程序 基于协同过滤算法的的校园音乐推荐系统

文章目录 项目介绍具体实现截图技术介绍mvc设计模式小程序框架以及目录结构介绍错误处理和异常处理java类核心代码部分展示详细视频演示源码获取 项目介绍 校园音乐推荐系统设计的目的在于帮助学校的管理者能够更加高效轻松地进行日常的管理工作,所以作为一个工具&…

第一章 Linux安装 -- 安装Debian 12操作系统(四)

文章目录 2.3.4 安装Debian 12操作系统 2.3.4 安装Debian 12操作系统 虚拟机的创建参照前面2.3.1.3节里的步骤创建,这里不再详述。 下面就开始安装Debian 12系统了,单击“开启此虚拟机”,如图1-161虚拟机主界面。 图1-161 虚拟机主界面 弹…

微服务架构面试内容整理-Hystrix

Hystrix 是由 Netflix 开发的一个用于处理分布式系统中的延迟和故障的库,主要用于实现熔断器模式。它帮助开发者确保系统的稳定性和可用性,防止单个服务的故障影响整个系统。以下是 Hystrix 的主要特点、工作原理和使用场景: 主要特点 1. 熔断器模式: 通过监控服务调用的成…