1. 重学webpack——webpack5.0基本概念

推荐:《webpack学完这些就够了》

《webpack学完这些就够了》该专题主要讲述webpack4.x从入门到成仙的学习笔记,配置和原理应有尽有。现在由于webpack5.0的诞生,打算从现在开始从0开始写一遍webpack5.0的学习笔记,与大家一起分享学习。

以下是本节正文:

1. webpack基本概念

  • webpack支持CommonJs和ES Module

  • pacakge.jsonscripts中,dev中原先配置使用的webpack-dev-server,现在只小改成serve,这只是脚本上的写法区别,装还是依旧要装webpack-dev-server这个依赖的

  • webpack5可以不写webpack配置,会根据默认配置来打包。如果你写了配置,名字为webpack.config.js,那么在package.json的执行脚本scripts中不需要指定配置名称,如果配置不是webpack.config.js,比如是webpack.base.js,那么脚本中就需要配置名称,配置举例:"build":"webpack --config webpack.base.js"

  • mode属性(webpack4.x引入的)表示打包的模式,值有:

    • production,是默认值:
      • 表示启用生产的插件编译,打包结果压缩的,运行时不打印debug信息,静态文件不包括sourcemap。
      • 默认会启用各种性能优化的功能,包括构建结果优化以及webpack运行性能优化。
      • 会将process.env.NODE_ENV设置为production
      • 会启用的插件有:
        • FlagDependencyUsagePlugin
        • FlagIncludedChunksPlugin
        • ModuleConcatenationPlugin
        • NoEmitOnErrorsPlugin
        • OccurrenceOrderPlugin
        • SideEffectsFlagPlugin
        • UglifyJsPlugin
    • development:
      • 表示启用开发的插件编译,打包结果不进行代码加锁,运行时打印debug信息,包含sourcemap文件。
      • 还会更价快速的增量编译构建(这是面试点)
      • 会将process.env.NODE_ENV设置为development
      • 会启用的插件:
        • NamedChunksPlugin,这个插件的作用就是:打包后的结果代码块显示名称,而不是数字代替代码块名称,会更加直观能够看到是哪个代码块
        • ``NamedModulesPlugin`,这个插件的作用就是:打包后的结果模块显示名称,而不是数字代替模块名称,会更加直观能够看到是哪个模块
    • none,表示既不使用生产的插件也不使用开发的插件,打包结果也没有混淆的
  • webpack只能理解jsjson文件,如果需要处理其他文件,那么就需要loader来转换,比如你要转换.txt格式的文件,那么就可以使用raw-loader来转换成一个module,取值要用.default来取

  • raw-loader只能解析原生文件,比如.txt.json.md等里面都是字符串的文件

  • loader主要是转换某些模块,对模块的源码进行改变。而plugin可以用于执行范围更广的任务,比如:打包优化、资源管理、注入环境变量等,plugin会贯穿整个生命周期

  • 老的html-webpack-plugin默认插入页面是在body中的,但是新的是在header中,并且给script标签加了一个defer,defer表示即便在header中,也不会阻塞body中的加载与执行,会等到整个页面都解析完毕后再执行

    • 面试点defer与async的区别

      • 解答:
        • 这两者都可以是script中的属性
        • defer,延迟的意思,表示脚本会被延迟到整个页面解析完毕后再运行。所以,在script标签中加defer属性,相当于告诉浏览器立即下载,但延迟到整个页面解析完毕后再执行。如果有多个defer,那么第一个延迟脚本会优先于第一个延迟脚本,这是因为html5规范要求脚本按照他们出现的先后顺序执行。
        • async,异步的意思,与defer类似,告诉浏览器立即下载,但是等到页面解析完毕后再执行,但是跟defer的区别是:async并不保证按照它的先后顺序执行。指定async属性的目的是不让页面等待脚本下载和执行,从而异步加载其他内容,这适用于之间互不依赖的各个脚本
    • 面试点:deferasync的作用是什么?

      • 解答:
        • 作用是告诉浏览器立即下载,但是等到页面解析完毕后再执行,只不过多个deferasync的时候,前者按照出现的先后顺序,后者不保证按照先后顺序执行
        • 具体:当网页交给浏览器的HTML解析器转变成一系列的词语(Token),解释器根据词语构建节点(Node)形成DOM树。因为JS代码可能会修改DOM树的结构,所以节点是js代码的话,就需要停止当前DOM树的创建,知道js的资源加载冰杯js引擎执行后才继续DOM树的创建,这里就会产生阻塞,出现白屏问题。
          • 当然引起白屏问题原因很多,脚本阻塞是其中一点,我们就可以使用asyncdefer属性来解决。当然最稳妥的版本还是把script标签放在body底部,没有兼容问题,没有白屏问题,没有执行顺序问题。

      问到deferasync问题,就答上面的,都答上就不会错

    • **引申面试点:**引起白屏问题的原因有哪些,分别怎么解决?

1. 开发环境与生产环境的基本需求

  • 开发环境
    • 需要生成sourcemap文件
    • 需要打印debug信息
    • 需要live reloadhot reload的功能
  • 生产环境
    • 可能需要分离css成单独的文件,以便多个页面共享同一个CSS文件
    • 需要压缩HTML/CSS/JS代码
    • 需要压缩图片

2.如何区分开发环境与生产环境

a.模块内设置环境变量(传递到模块内)
  • webpack配置文件中的mode用来模块内process.env.NODE_ENV
// webpack.config.js
module.exporst = {
    mode: 'development'
}
// 模块中,也就是例如index.js中
console.log(process.env.NODE_ENV) // 会打印development
  • --mode用来设置模块内process.env.NODE_ENV
// package.json中
"script": {
    "build": "webpack --mode=production",
    "dev": "webpack serve --mode=development"
}
// 模块中,也就是例如index.js中
console.log(process.env.NODE_ENV) // 当使用npm run build的时候,会打印production,dev的时候回打印development
// node环境中,没有作用
// webpack配置中,没有作用
  • DefinePlugin用来设置模块内的全局变量

    • 设置全局变量(不是window),所有模块都能读取该变量的值

    • 可以在任一模块内通过process.env.NODE_ENV获取当前的环境变量

    • 但无法先node环境(webpack配置文件)中获取当前环境变量

      **面试题:**为什么所有的模块中都能获取到process.env.NODE_ENV,是挂在到window下或者global下了吗?

      答案:不是的,并没有挂在到任何下面,只是编译时纯粹的一个字符串替换,也就是看到了process.env.NODE_ENV,替换成了对应的值。并不会挂载在某变量下,或者定义任何变量。

      **面试题:**为什么DefinePlugin中的值需要JSON.stringify包一层,而不是直接用字符串?

      答案:因为如果直接用字符串,编译后是一个变量,而如果包了一层JSON.stringify,相当于单引号字符串外面套了一层双引号,编译后就是带引号的字符串。

      为什么这个插件编译结果是这样的呢? 因为会将值这个字符串替换成模块中的变量,那么如果值这个字符串再包一层引号,替换过去就相当于模块中的变量包了一层引号,那就是字符串了

// webpack.config.js
plugin: [
    new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify('development'), // 会显示与webpack内部的process.env.NODE_ENV冲突,虽然冲突,结果还是这个优先级最高
        'NODE_ENV': JSON.stringify('production')'NODE_ENV_yh': "'yh'", // 这样跟JSON.stringify('yh')一样
    })
]
// index.js
console.log(NODE_ENV)
注意( 面试点):如果上面三个都设置了,谁的优先级最高?
答案:优先级: DefinePlugin > --mode > mode
b.webpack配置文件中设置环境变量

dotenv这个库能够读取对应的文件,从而设置环境变量
该方法只对webpack配置文件有效,且优先级小于script设置的。

// .env文件
NODE_ENV=developmentyy
// webpack.config.js文件
// 从文件加载环境变量
require('dotenv').config({path: '.env'})
console.log(process.env.NODE_ENV) // developmentyy
c.webpack配置文件和模块中设置环境变量
  • --env用来设置webpack配置文件的函数参数

    --env会将值传递给webpack.config.js导出的函数

// package.json中
"script": {
    "build": "webpack --env=production",
    "dev": "webpack serve --env=development"
}

// webpack.config.js配置中module.export要改写成一个函数,通过函数参数传入env
module.exports = (env, argv) => {
    console.log(env); // 如果你是npm run build,那么env.production为true,如果是npm run dev,那么env.development为true
    console.log(argv); // 值为{env: env对象}
    return {
        ... // 返回配置对象
    }
}
  • cross-env用来设置模块和配置文件两者的process.env.NODE_ENV
    • 相当于给shell设置环境变量,在webpack.config.js中可以拿到,也可以在模块中拿到
    • cross-env这个库支持跨平台设置环境变量,在windows和mac下其实是这么设置环境变量的
      • set NODE_ENV=production && webpack,这是给windows设置环境变量
      • export NODE_ENV=production && webpack,这是给mac设置环境变量
// package.json中
"script": {
    "build": "cross-env NODE_ENV=production webpack", // 用cross-env 不需要&& 符号,但是用set或export则需要&&符号
}

以上的模块内,指的是module,比如index.js中打印console.log(process.env.NODE_ENV)

以上的webpack配置文件,指的是类似webpack.config.js这类配置文件,在这类文件内打印console.log(process.env.NODE_ENV)

以上的系统环境内,指的是给操作系统设置环境变量,一般再shell中设置

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值