webpack5学习进阶:多页面应用、Tree Shaking、PWA、Shimming

2023-10-22 14:20

本文主要是介绍webpack5学习进阶:多页面应用、Tree Shaking、PWA、Shimming,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

      • 一、多页面应用
        • 1、entry 配置
          • 1.1、将两个本地文件打包在一起
          • 1.2、还可以打包第三方库文件
          • 1.3、多页面打包
        • 2、index.html 模板配置
        • 3、多页面环境搭建
      • 二、Tree Shaking(摇树优化)
        • 1、配置 Tree Shaking
        • 2、设置 sideEffects
        • 3、对全局 css 的影响
      • 三、PWA (开启离线服务)
        • 1、在线服务
        • 2、添加 Workbox 实现 PWA
        • 3、注册 Service-Worker
      • 四、Shimming (预置依赖)
        • 1、预置全局变量
        • 2、改变 this 指向
        • 3、全局导出一个模块(exports)
        • 4、Polyfils
          • 4.1、加载 polyfiles
          • 4.2、优化 polyfiles

一、多页面应用

在实际的项目开发中,一个完整的系统不会将所有的功能都放在一个网页里,这是因为会导致网页的性能不佳;实际的做法是,按照功能模块来划分为多个单页面应用,每一个单页面应用又生成一个 HTML 文件,随着业务的发展,更多的多页应用可以被逐渐的加到这个项目里;

1、entry 配置
1.1、将两个本地文件打包在一起
entry:['./src/app1.js', './src/app2.js']
//或者
entry:{main:{import:['./src/app1.js', './src/app2.js']}
}

打包过后,app1.js 和 app2.js 都会被打包进 dist/main.js 文件中,按照数组里面的前后顺序,webpack 会将前面的文件先打包,并且放在 main.js 的上面;

1.2、还可以打包第三方库文件
entry:['./src/app1.js', './src/app2.js', 'lodash']
1.3、多页面打包
entry:{app1:'./src/app1.js',app2:'./src/app2.js',
}

这种配置 webpack 会打包出两个文件,dist/app1.js 和 dist/app2.js ;

2、index.html 模板配置

新建一个 html 页面,动态获取 html-webpack-plugin 插件配置的 title,将多个 js 文件分别打包到对应的 html 文件中;

<title><%= htmlWebpackPlugin.options.title %></title>

在配置文件中

plugins:[new HtmlWebpackPlugin({title:'nihao xxs', template:'./index.html',inject:'body',chunks:['app1'],filename:'http:www.a.com/'})]

title:html 的 title 名称
template:打包 html 页面的模板
inject:js 在打包后的 html 中引入的位置
chunks:默认情况下,多入口文件打包出来的 js 文件都会放到打包后的 html 页面中,如果想载入指定的 js,可以在 chunks 数组中配置对应的 js 名称;
filename:配置包的前缀,一般比较大的项目会用到;

3、多页面环境搭建

添加多个 HtmlWebpackPlugin 插件配置:

plugins:[new HtmlWebpackPlugin({filename:'index1.html',title:'nihao xxs', template:'./index.html',inject:'body',chunks:['app1']}),new HtmlWebpackPlugin({filename:'index2.html',title:'nihao xxs', template:'./index.html',inject:'body',chunks:['app2']})]

不设置 chunks 的话会默认两个打包后的 html 文件都引入所有的 js,设置 chunks 之后,只会引入设置的 js;

我们还可以设置其他的一些东西:
1、打包后的 html 放到指定文件夹下,只需要修改 filename 路径,在路径上加一个文件夹名称,打包就会自动生成一个文件夹并把 html 放进去;

plugins:[new HtmlWebpackPlugin({filename:'chunk/index1.html',template:'./index.html',})]

2、将 js 页放到对应 html 文件夹下,也是修改入口文件的 filename 路径;

entry:{app1:{import:'./src/app.js',filename:'chunk/[name].js'}},

二、Tree Shaking(摇树优化)

Tree Shaking 是 webpack 内置的一个优化,主要功能就是去除没有用到代码。因为 JavaScript 大多数是要通过加载的,加载的文件越小,性能越好,所以 Tree-shaking 对于优化 JavaScript 很有意义。

Tree-shaking 主要依赖于 ES6 的模块化 import 和 export,在 production 环境默认开启;

注意:
1、Tree Shaking 只支持 ESMAScript 的引入方式,不支持 Common JS 的引入方式
2、在引入模块时就应该避免将全部引入,应该引入局部才可以触发 tree shaking 机制

1、配置 Tree Shaking
//test.js
import {add,mun} from './app1'
console.log(add(1,2))//app.js
export const add = function(a,b){return a+b
}
export const mun = function(a,b){return a
}

webpack中开启 Tree Sharking:

optimization:{usedExports:true
}

开发环境打包结果:
在这里插入图片描述
这里只暴露了 add 方法,并且提示 mun 未被导出;哪怕引入了,但是未被使用,依然会被认为是死代码,webpack5 在打包的时候会自动过滤掉死代码;

2、设置 sideEffects

如果在一个纯粹的 ESMScript 模块项目中,很容易识别出哪些文件有副作用;然而,我们实际开发的项目却无法达到这种纯度,所以,此时就必要提示 webpack compiler 哪些代码是“纯粹部分”。 通过 package.json 文件中的 sideEffects 属性;

1、sideEffects 默认为 true, 告诉 Webpack ,所有文件都有副作用,他们不能被 Tree Shaking。
2、sideEffects 为 false 时,告诉 Webpack ,没有文件是有副作用的,他们都可以 Tree Shaking。
3、sideEffects 为一个数组时,告诉 Webpack ,数组中那些文件不要进行 Tree Shaking,其他的可以 Tree Shaking。

在 package.json 文件中:

{"description": "","sideEffects":true,
}
3、对全局 css 的影响

正常不设置 sideEffects 的话,我们通过 import 引入一个全局的样式文件,webpack 默认是可以正常打包使用的;但是如果设置 sideEffects 为 false 时,这时候所有的文件都会被 Tree Shaking;我们需要单独设置 css 文件文件不要 Tree Shaking;

{"description": "","sideEffects":["*.css"],
}

所以我的理解是:开启 Tree Sharking 后 sideEffects 默认值为 true,这个时候 Tree Sharking 只处理没有关联关系的 js 代码,不处理引入的文件;如果设置 sideEffects 为 false,那么 import 引入的文件也放入到 Tree Sharking 中进行修剪处理;sideEffects 是控制 Tree Sharking 处理文件直接依赖关系的开关;

三、PWA (开启离线服务)

渐进式网络应用程序:简称 PWA,它可以提供类似于 native(原生)应用程序体验的 web app(web 应用程序),换句话就说说我们可以在浏览器端能够实现类似于原生应用程序的体验;

PWA 可以做的事情很多,其中最重要的就是在离线的情况下,应用程序能够继续运行的功能,它是通过 service worker 的 web 技术实现的;

1、在线服务

通常情况下,用户通过网络访问 web app ,浏览器会与一个提供所需资源的 server 通讯;这里我们来看看非离线环境下项目的运行效果;
1、安装 http-server

npm i http-server -D

2、在 package.json 定义自己的 npm 脚本

"scripts":{"start":"http-server dist"
}

用 http-server 来编译运行 dist 下的内容
3、启动服务

npm start

webpack-dev-server 和 http-server 都是在线的服务;在线服务在服务停止后,浏览器是无法正常访问到网页的;同时在线服务会把启动服务时编译的代码放在内存里,也就是说当我们修改代码之后重新启动服务,这个时候并不会把修改同步打包到 dist 文件夹下面;
4、如果启动服务想同步打包更新 dist 文件

devServer:{devMiddleware:{writeToDisk:true}
}

这个配置没什么太大意义,只是介绍一下有这个功能;

2、添加 Workbox 实现 PWA

1、安装 workbox-webpack-plugin 插件

npm i workbox-webpack-plugin -D

2、安装成功之后修改配置文件

const WorkboxPlugin = require("workbox-webpack-plugin")
module.exports={plugins:[new WorkboxPlugin.GenerateSW({clientsClaim:true, //帮助快速启用 service-workerskipWaiting:true //跳出等待,不允许遗留任何旧的 service-worker})]
}

3、打包编译
这个时候会发现多了两个文件:workbox.js 、service-worker.js;添加成功之后还需要进行下一步:注册 service-worker;

3、注册 Service-Worker

注册 service-worker 实现离线浏览页面的功能;

//在入口文件中 业务代码中 app.js
//判断浏览器是否支持service-worker
if("serviceWorker" in navigator) {//页面资源加载完成之后执行下面函数window.addEventListener("load",()=>{navigator.serviceWorker.register("/service-worker.js").then(reg=>{console.log('注册成功')}).catch(err=>{console.log("注册失败”)})})
}

然后执行 npx webpack 打包,执行 npm start 启动服务;这里我们是通过 npm start 来启动服务的,所以必须重新打包;这样我们的离线服务就启动成功了;

为了实验效果,可以在控制台将服务停止,然后继续在浏览器刷新页面访问网页,是能正常访问的;

实现这个效果主要原理是:浏览器把我们的页面做了缓存,我们可以把这个缓存清理掉:新开个页面输入"chrome://serviceworker-internals" 然后点击 Unregister 按钮,这样缓存就被清理了,页面就不能正常访问了;

四、Shimming (预置依赖)

shimming 又称垫片,本身不是一种具体的使用方法,而是一种使用思路。比如 @babel/polyfill,他所解决的就是打包代码运行在低版本浏览器上时有些 api 不兼容的问题,这些行为就是 shimming;

1、预置全局变量

比如我们想将 lodash 暴露成一个全局变量,需要借助 webpack 提供的 providePlugin 来实现,无需安装,因为是 webpack 内部提供的;

const webpack = require('webpack')
module.exports={plugins:[new webpack.providePlugin({_:lodash})]
}

这样,lodash 就是一个全局的变量了;

2、改变 this 指向

如果一些模块依赖的 this 指向的是 window,当它运行在 CommonJS 上下文中的时候,这就会出现问题,因为此时的 this 指向的是 module.exports ;这个时候我们需要通过 imports-loader 来改变 this;
安装

npm i imports-loader -D

配置

module:{rules:[{test:require.resolve('./src/index.js'),use:"imports-loader?wrapper=window"}]
}

这里的 test 需要加载某一个文件,所以借助 require.resolve 方法;然后 imports-loader 后面问号拼接一个 wrapper=window ,这是将包里面的 this 指向 window;

3、全局导出一个模块(exports)

将某些不支持模块化规范的模块所声明的全局变量、局部变量作为模块内容导出;
安装

npm i exports-loader -D

配置

module:{rules:[{test:require.resolve('./src/index.js'),loader:'exports-loader',options:{type:'commonjs',exports:["hello", "multiple help.parse parse"]}}]
}

需要导出的模块

const hello = "hello webpack"
const help = {parse:function(){console.log("i need help")}
}

type:模块导出的类型,我们指定的是 CommonJS
exports:导出的变量,我们导出的是 hello,multiple 表示导出局部变量
参数设置:参考 exports-loader

4、Polyfils

polyfill(polyfiller),指的是一个代码块;这个代码块向开发者提供了一种技术, 这种技术可以让浏览器提供原生支持,抹平不同浏览器对 API 兼容性的差异;你只需要把需要的Polyfill引入到你的程序里,就可以正常使用了;

4.1、加载 polyfiles

安装

npm i @babel/polyfile -D

引入

import "@babel/polyfile"
4.2、优化 polyfiles

如果在全局引入整个 polyfiles 包,转化之后打包的体积会比较大,而且还会污染全局环境;所以我们可以通过 babel-preset-env 包通过 browserslist 来指定那些浏览器、那些浏览器的版本进行转译;
我们要使用 babel 所以要先安装 babel 相关的 loader:

npm i babel-loader @babel/core @babel/preset-env core-js@3 -D

配置

module:{rules:[test:/\.js$/,exclude:/node_modules/,use:{loader:'babel-loader',options:{presets:[["@babel/preset-env",targets:["last 1 version","> 1%"],useBuiltIns:'usage',corejs:3]]}}]
}

配置完成之后,我们就不需要在手动引入 @babel/polyfile 包了;同时如果已经引入了,需要删除掉;

这篇关于webpack5学习进阶:多页面应用、Tree Shaking、PWA、Shimming的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/262015

相关文章

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

C语言中位操作的实际应用举例

《C语言中位操作的实际应用举例》:本文主要介绍C语言中位操作的实际应用,总结了位操作的使用场景,并指出了需要注意的问题,如可读性、平台依赖性和溢出风险,文中通过代码介绍的非常详细,需要的朋友可以参... 目录1. 嵌入式系统与硬件寄存器操作2. 网络协议解析3. 图像处理与颜色编码4. 高效处理布尔标志集合

Java中的Lambda表达式及其应用小结

《Java中的Lambda表达式及其应用小结》Java中的Lambda表达式是一项极具创新性的特性,它使得Java代码更加简洁和高效,尤其是在集合操作和并行处理方面,:本文主要介绍Java中的La... 目录前言1. 什么是Lambda表达式?2. Lambda表达式的基本语法例子1:最简单的Lambda表

Python结合PyWebView库打造跨平台桌面应用

《Python结合PyWebView库打造跨平台桌面应用》随着Web技术的发展,将HTML/CSS/JavaScript与Python结合构建桌面应用成为可能,本文将系统讲解如何使用PyWebView... 目录一、技术原理与优势分析1.1 架构原理1.2 核心优势二、开发环境搭建2.1 安装依赖2.2 验

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

SpringShell命令行之交互式Shell应用开发方式

《SpringShell命令行之交互式Shell应用开发方式》本文将深入探讨SpringShell的核心特性、实现方式及应用场景,帮助开发者掌握这一强大工具,具有很好的参考价值,希望对大家有所帮助,如... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定

SpringBoot应用中出现的Full GC问题的场景与解决

《SpringBoot应用中出现的FullGC问题的场景与解决》这篇文章主要为大家详细介绍了SpringBoot应用中出现的FullGC问题的场景与解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录Full GC的原理与触发条件原理触发条件对Spring Boot应用的影响示例代码优化建议结论F

MySQL 分区与分库分表策略应用小结

《MySQL分区与分库分表策略应用小结》在大数据量、复杂查询和高并发的应用场景下,单一数据库往往难以满足性能和扩展性的要求,本文将详细介绍这两种策略的基本概念、实现方法及优缺点,并通过实际案例展示如... 目录mysql 分区与分库分表策略1. 数据库水平拆分的背景2. MySQL 分区策略2.1 分区概念

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印