webpack的一些知识

时间:2024-03-06 18:19:12

核心

  • webpack 是用来搭建前端工程的
  • 它运行在node环境中,它所做的事情,简单来说,就是打包
  • 具体来说,就是以某个模块作为入口,根据入口分析出所有模块的依赖关系,然后对各种模块进行合并、压缩,形成最终的打包结果
  • 在webpack的世界中,一切都是模块

体验

按照习惯,所有的模块均放置在 src 目录中

  1. 安装依赖
  2. 编写多个模块 随意模块,可以是js、图片、音视频,以入口模块为起点,形成依赖关系
  3. 运行npm run build命令,进行打包
  4. 查看打包结果 ,打包结果放置在dist目录中

不难发现,webpack给我们带来了以下好处:

  1. 可以大胆的使用任意模块化标准,无须担心兼容性问题,因为webpack完成打包后,已经没有了任何模块化语句
  2. 可以将一些非 js 代码也视为模块,这样可以对 css 、图片等资源进行更加细粒度的划分
  3. 在前端开发中,也可以使用npm。webpack不会运行源代码,无论是自己写的模块还是通过npm安装的模块,webpack 一律认为是依赖,最终合并到打包结果中
  4. 非常适合开发单页应用,单页应用是前端用户体验最好的web应用,所谓单页应用,是指只有一个html页面,页面中没有任何内容,所有的内容均靠js生成,要优雅的实现单页应用,最好依托于前端框架,比如vue、react
  • webpack 给我们开发带来的变化远不止于此

页面模版

  • 对于单页应用而言,只有一个空白的页面,所有内容都靠 js 代码创建
  • webpack 会自动生成一个页面,并且在页面中会自动加入对 js 和 css 的引用
  • 它生成页面时,参考的是 public/index.html,其称之为页面模版

public目录

  • webpack 会非常暴力的将 public 目录中的所有文件(除页面模板外),复制到打包结果中

开发服务器

  • 如果每次修改完代码,都要经过 打包-> 运行,太过麻烦了
  • 在开发阶段,我们可以运行 npm run serve 命令获得更好的打包体验
  • 该命令会让 webpack 启动一个开发服务器
  • 在这个阶段,webpack并不会形成打包结果文件,而是把打包的内容放到内存中,当我们请求服务器时,服务器从内存中给予我们打包结果
  • 与此同时,当源码发生变动时,webpack会自动重新打包,同时刷新页面以访问到最新的打包结果

文件缓存

  • 除了页面外,其他的资源在打包完成后,文件名多了一些奇奇怪怪的字符
  • 例如:js/app-22324a23.js
  • 其中,22324a23 这样的字符称之为hash,它会随着模块内容的变化而变化
  • 源码内容不变,hash不变;源码内容变化,hash变化
  • 之所以这样做,是因为生产环境中,浏览器会对除页面外的静态资源进行缓存
  • 如果不设置hash值,一旦代码更新,浏览器还会使用之前缓存的结果,无法使用最新的代码
  • **webpack会在打包时自动处理 hash 值,并不会对我们写代码造成任何影响,但作为一个前端开发者,有必要了解一下

资源路径

  • 除代码和样式模块外,其他模块被视为资源模块

  • 值得注意的是,资源模块在源代码中的路径和打包后的路径是不一样的,这就导致了我们在编写代码的时候,根本无法知晓资源最终的路径

  • 最常见的例子就是在css中使用背景图片

  • .container {
        /* 背景图使用了源码中的路径 */
        background: url('../assets/1.jpg');
    }
    
  • 这里可以正常工作,因为webpack 可以非常智能的发现这一点,对于css中的路径,webpack在打包时,会将其自动转为打包结果的路径

  • 上面的例子可能被转换为下面的代码:

  • .container {
        background: url(/img/1234aa.jpg);
    }
    
  • 但是我们要通过 js 动态的使用路径,webpack 是无法识别的

// 打包前
const url = './assets/1.png'; // 路径无法被转换
img.src = url;

// 打包后
const url = './assets/1.png'; // 错误
img.src = url;
  • 正确的做法是,通过模块化的方式导入资源,并获取资源路径
// 打包前
import url from './assets/1.png'; // 打包后,url得到的是打包后的路径
img.src = url;

// 打包后
const url = '/img/1234aa.png'; // 正确
img.src = url;

缺省的文件和后缀名

  • 导入模块时,所有 js 模块均可省略 .js ,若导入的模块文件名为 index.js ,可省略文件名
import './home'; // home.js
import './movie'; // 若movie是一个目录,则导入的是./movie/index.js

路径别名

  • 随着代码量的增加,不可避免的是形成层级深的目录
  • webpack 提供了别名供我们快速定位到 ./src 目录,通常,该别名为@

js 兼容性

  • 当webpack 读取到 js 代码时,会自动对其进行兼容性处理
  • 具体的处理方案涉及两个配置文件
    1. babel.config.js: 配置该文件,可以设置对哪些 js 代码进行降级处理
    2. .browserslistrc: 配置该文件,可以设置在降级时,要兼容哪些浏览器,兼容的范围越广,降级产生的代码就越多,自然打包后的体积就越大

打包压缩

  • webpack 在打包时,会对所有的 js 和 css 代码进行压缩
  • 对于 js ,除了压缩外,还会对其中的各种名称进行混淆
  • 混淆的作用一是为了进一步压缩包体积,二是为了我们的代码更难被其他人理解利用

源码地图

  • source map
  • 打包后的结果是很难阅读的
  • 如果代码报错,我们将难以得知出错的代码行
  • 可以发现,打包后都会跟上一个同名的、后缀为 .map 的文件,该文件就保存了原始代码的内容
  • 这个内容人类是看不懂的,但是浏览器可以看懂
  • 代码报错时,浏览器定位到源码地图中的对应代码,而不是把真实报错的代码展示给我们

css工程化

  • webpack 能够识别所有的样式代码,包括 css、 less、sass、stylus
  • 打包时,便会将它们转换为纯正的 css
自动厂商前缀
  • css有很多兼容性问题,解决这些问题最常见的办法就是加上厂商前缀
  • webpack 会根据 .browserlistrc 中指定的浏览器范围,按需自动加上厂商前缀
css module
  • css 文件多了后,为了保证它们之间没有冲突的类样式
  • 靠的是 css module
  • 当样式文件以 xxx.module.xxx 的方式命名时,webpack 会将该文件当成一个开启了 css module 的文件
  • 然后文件中的所有类名都将被 hash 化
  • 我们在使用类名时,通过下面的方式得知打包后的类名
import './index.module.less';
dom.classList.add('container'); // ❌ 最终的类名可不是这个

// styles 是一个对象,里面映射了源码类名和打包类名的关系
import styles from './index.module.less';
dom.classList.add(styles.container); // ✅ 属性container中记录的就是container转换后的类名

其实webpack 并没有这么强大

  • 实际上,它就是通过插件(plugin) 和加载器(loader)将这些技术整合在一起
  • .browserslistrc :表达适配的浏览器范围,会被工程化中的其他技术所使用
  • babel.config.js :babel的配置文件,做 js 降级处理
  • postcss.config.js :postcss 的配置文件,做css代码转换
  • webpack.config.js :webpack 的配置文件,整合其他工程化技术,以及配置打包细节、开发服务器、路径别名等

对我们的影响(important)

  1. 学会访问开发服务器查看效果
  2. 学会动态获取资源文件路径(import url from ‘./assets/1.jpg’)
  3. 学会省略文件和后缀名(js文件和index.js文件)
  4. 学会使用别名简化导入代码(import ‘@/a/a1’)
  5. 学会使用 css module(index.module.less)