涉及到的方面较广,有经验的大佬可选择性跳过。
基础
1.webpack打包本质
本质就是nodejs去执行webpack脚本,由webpack脚本对项目各个文件进行必要的编译(翻译/字符串替换)再输出到某个目录。即可以简单理解为webpack是一个nodejs的小程序,功能是读取文件内容,进行字符串修改操作后,输出内容。
因此具体的前端js文件中是不可使用nodejs的东西的,因为它们没有被nodejs运行。至于process变量,在webpack打包中时的确就是nodejs的process;在最终的浏览器中,process只是一个最简单的副本对象,拥有与nodejs的process相似的数据内容,但是并不是同一对象。
2.import from 和require
webpack相关脚本中的require和我们前端js文件中使用的require不是一回事。
你可以发现在webpack相关文件中,全部使用require导入,这个require就是nodejs模块化的关键字。
而具体前端js文件中,使用到的require是由webpack提供的一个函数,功能类似但更加强大。主要能力有:完成导入,参数可以省略部分后缀名(需要配置)、是目录时自动寻找该目录下的index.js并导入、能够使用别名(alias,需要配置)、导入图片(实际导入为base64编码后的字符串)、提供给loader以扩展导入vue和sass等更多文件。
至于import from
,实际上是语法糖,import img from './a.jpg'
被处理为const img=require('./a.jpg')
,这个require就是上述的require,是webpack提供的一个函数。
注意:对于js模块化,你可能还需要了解下CommonJS和ES6规范的语法形式:js require/exports和import/export。
另外nodejs中借助babel相关包,同样可以提供import from的语法糖,但是它的这个import from只是换成nodejs的关键字require,并没有像webpack那样处理(实际上也不需要)。我这里只是想提醒下这个差异,毕竟前端使用nodejs开发时,并不需要nodejs跑我们的前端js文件,因此我们的前端文件拥有更多可能的自定义语法、格式、功能
正文
1.webpack模块化处理解析配置
即webpack的resolve配置:解析(resolve)
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),//此resolve是外面定义的一个函数,用于生成绝对路径
'@assets': resolve('src/assets')
}
},
上面require提到的别名、可省略扩展名在这里配置。
至于require函数中的路径参数,具体的解析法则如下:webpack 如何解析代码模块路径
1.解析相对路径
查找相对当前模块的路径下是否有对应文件或文件夹
是文件则直接加载
是文件夹则继续查找文件夹下的 package.json 文件
有 package.json 文件则按照文件中 main 字段的文件名来查找文件
无 package.json 或者无 main 字段则查找 index.js 文件.
2.解析模块名
查找当前文件目录下,父级目录及以上目录下的 node_modules 文件夹,看是否有对应名称的模块
3.解析绝对路径
直接查找对应路径的文件
2.图片的去向
一般受url-loader和file-loader控制。
具体可以直接去看他们文档。简单而言url-loader把小图片变为base64的字符串然后直接替换路径;file-loader把url-loader没处理的那些大图片给复制到指定位置(用户设置),同时把原来的的路径替换成publicPath+指定位置(用户设置)
。
这里的publicPath设置有讲究,因为相对路径中css和js的起始路径不一致。
如publicPath:'./'
,那么在打包后浏览器环境下,css的./
是指css所在路径;而js中的./
是指浏览器当前地址栏的url的路径目录。因此假如/mycss/a.css
中有url(./a.jpg)
,浏览器认为图片在/mycss/a.jpg
;假如在/a/b/
网址下,js设置img.src=url(./a.jpg)
,浏览器认为图片在/a/b/a.jpg
这个时候我们可以调整file-loader处理图片时的参数,单独为其设置publicPath而不是使用全局publicPath,这比较灵活,对应上自己打包后的图片路径即可
3.图片路径
1.css中:
问题主要是"路径别名",若要使用,路径前要加个~
,即url('~@assets/a.jpg')
之类的。
因为css中我们无法使用require函数,url-loader和file-loader不能确定解析方式。比如说我们有个别名@
代表src目录,但是恰好我们目录下有个@
文件夹,那么就产生了二义性无法确定。因此默认情况下,css中所有路径都不认别名,除非路径开头有个~
,指明要额外使用模块路径解析
2.html中:
同css,新版本中好像不用加~
也行,见仁见智
3.js中:
不用写~
,require一定使用模块路径解析。另外由于js比起他们多了动态设置,设置图片src时,没有各种loader帮我们处理了,很可能对不上打包后的目录结构。这要求我们必须正确把地址写成最终打包后的图片相对地址,十分不利于修改和维护
正确方法是用require函数(webpack提供),这个是运行时也存在的,它能够让路径参数的解析仍然从开发目录开始计算,计算法则同上所述,因此我们放心在这里写开发时的图片路径。当然,这个require返回值也如上所述,对于图片文件返回base64编码后字符串。
注意require中路径别名问题。使用别名时,需要把别名字符串的部分直接包含在参数中。即
let number=1, p1='./', p2='@assets'
img.src=require(`./assets/img${number}.jpg`)//正确
img.src=require(`@assets/img${number}.jpg`)//正确
img.src=require(`${p1}assets/img${number}.jpg`)//正确
img.src=require(`${p2}/img${number}.jpg`)//错误
我也不知道这个是bug还是什么鬼了,有了解的大佬可以说下