当前位置: 首页 > 后端技术 > Node.js

【精进系列】webpack相关知识

时间:2023-04-03 16:31:45 Node.js

这次主要学习webpack框架的相关知识。webpack是解决前端开发模块化问题的打包前端框架。应用场景及纵向对比提到webpack,大家肯定会想到gulp、grunt等框架,那么webpack是做什么的呢?他和其他框架有什么区别?我们一起来分析一下。本段我们主要对webpack和gulp进行纵向对比分析:webpack的根本任务是对一个文件中引用的另一个文件进行打包打包。gulp的根本任务是实现自动化。其实我们可以写一个node脚本来压缩所有的js文件。Gulp就是打包脚本来帮我们做这些事情。另外:webpack其实可以压缩js文件,但这只是在完成打包任务的上下文中额外完成的任务。使用场景呢?什么情况下应该使用webpack,什么情况下应该使用gulp?在我看来,这就是旁观者所见。如果你说你在开发项目中是为了打包和模块化,那么你就必须要用webpack,而如果你想解析sass直接放到html中,那么这个用webpack就可以实现,而且在开发过程中也很容易搞定包装过程。但是,除了第一次,你还想意识到,当你上线构建,上传图片到CDN,替换链接的时候,就需要另外引入gulp。webpack和gulp都有自己的优点和缺点。分析完这两个框架,就可以如鱼得水使用了。基本配置项基本配置项。我们先说说如何定义基本的配置项。首先是我们可以使用shell方式来定义配置,然后在命令行中写入。然而,这种方法并不好。如果配置项太多,执行的命令会很长。因此,我们一般采用配置文件的方式。constpath=require('path');module.exports={//entry代表一个entry,Webpack的第一步构建会从Entry开始,可以抽象为一个input。//类型可以是字符串|对象|arrayentry:'./app/entry',//只有1个条目,也只有1个文件条目:['./app/entry1','./app/entry2'],//只有一个1个条目,条目有2个文件条目:{//有2个条目a:'./app/entry-a',b:['./app/entry-b1','./app/entry-b2']},//如何输出结果:Webpack经过一系列处理后,如何输出最终想要的代码。output:{//输出文件存放的目录必须是字符串类型的绝对路径。path:path.resolve(__dirname,'dist'),//输出文件的名称filename:'bundle.js',//完整名称filename:'[name].js',//当有多个条目时配置使用名称模板时,为不同的条目生成不同的文件名filename:'[chunkhash].js',//根据文件内容的哈希值生成文件名,用于浏览器长期缓存文件//发布到线上所有资源的URL前缀,字符串类型publicPath:'/assets/',//放到指定目录publicPath:'',//放到根目录publicPath:'https://cdn.example.com/',//放在CDN上//导出的库名,字符串类型//不填时,默认输出格式为匿名立即执行函数library:'MyLibrary',//导出库的类型,枚举类型,默认是var//可以是umd|umd2|commonjs2|常见问题|AMD|这个|变种|typepathinfo:true,//附加Chunk的文件名chunkFilename:'[id].js',chunkFilename:'[chunkhash].js',//JSONP异步加载资源时的回调函数名,需要与服务器一起使用jsonpFunction:'myWebpackJsonp',//生成的SourceMap文件的名称sourceMapFilename:'[file].map',//浏览器开发者工具中显示的源代码模块的名称devtoolModuleFilenameTemplate:'网络pack:///[resource-path]',//异步加载跨域资源的方式crossOriginLoading:'use-credentials',crossOriginLoading:'anonymous',crossOriginLoading:false,},//配置模块相关模块:{rules:[//配置Loader{test:/\.jsx?$/,//正则匹配打文件使用Loaderinclude:[//只打里面的文件path.resolve(__dirname,'app')],exclude:[//忽略path.resolve(__dirname,'app/demo-files')]],use:[//按顺序使用那些Loader,从后往前执行'style-loader',//直接使用Loader的名字{loader:'css-loader',options:{//传递一些参数给html-loader}}]},],noParse:[//不需要解析和处理的模块/special-library\.js$///使用正则匹配],},//配置插件plugins:[],//配置查找模块的规则resolve:{modules:[//查找模块根目录,数组类型,默认以node_modules为根目录'node_modules',path.resolve(__dirname,'app')],extensions:['.js','.json','.jsx','.css'],//模块别名的后缀名:{//模块别名配置,用于映射模块//将'module'映射到'new-module',同样的'module/path/file'也会被映射to'new-module/path/file''module':'new-module',//在使用尾随符号$之后,将'only-module'映射到'new-module',//但与上面不同的是,'module/path/file'不会被映射到'new-module/path/file''only-module$':'new-module',},alias:[//alias也支持使用数组进行更详细的配置{name:'module',//oldmodulealias:'new-module',//newmodule//是否只是一个映射模块,如果为true则只映射'module',如果为false'module/inner/path'也会被映射onlyModule:true,}],symlinks:true,//是否按照文件软链接搜索模块的路径descriptionFiles:['package.json'],//的描述文件themodulemainFields:['main'],//模块描述文件中描述入口的文件的字段名enforceExtension:false,//是否强制导入语句指定文件后缀},//输出文件性能检查配置性能:{hints:'warning',//出现性能问题时输出警告提示:'error',//出现性能问题时输出错误提示:false,//关闭性能检查maxAssetSize:200000,//最大文件大小(单位字节)maxEntrypointSize:400000,//最大入口文件大小(单位bytes)assetFilter:function(assetFilename){//过滤要检查的文件returnassetFilename.endsWith('.css')||assetFilename.endsWith('.js');}},devtool:'source-map',//配置source-map类型context:__dirname,//Webpack使用的根目录,字符串类型必须是绝对路径//配置输出代码目标的运行环境:'web',//浏览器,默认target:'webworker',//WebWorkertarget:'node',//Node.js,使用`require`语句加载Chunk代码target:'async-node',//Node.js,异步加载Chunk代码target:'node-webkit',//nw.jstarget:'electron-main',//electron,主线程target:'electron-renderer',//electron,渲染threadexternals:{//使用JavaScript运行环境提供的全局变量jquery:'jQuery'},stats:{//控制台输出日志控件assets:true,colors:true,errors:true,errorDetails:true,hash:true,},devServer:{//DevServer相关配置proxy:{//代理到后端服务接口'/api':'http://localhost:3000'},contentBase:path.join(__dirname,'public'),//配置DevServerHTTP服务器的文件根目录compress:true,//是否开启gzip压缩historyApiFallback:true,//是否开发HTML5HistoryAPI网页hot:true,//是否开启模块热替换功能https:false,//是否开启HTTPS模式},profile:true,//是否抓取性能Webpack构建的信息,用于分析导致构建性能不佳的原因cache:false,//是否开启缓存以提高构建速度watch:true,//是否开启watchOptions:{//监听模式选项//监听的文件或文件夹不监听,支持正则匹配默认为空ignored:/node_modules/,//监听到变化后,会等待300ms再执行动作,防止文件更新过快导致重新编译频率过高high//默认是300msaggregateTimeout:300,//判断文件是否改变就是不断的询问系统指定的文件是否有改变。默认情况下,它每秒请求1000次。output、loader、plugin分别代表entry、exit、loader、plugin。具体配置信息和其他配置项不再一一介绍。建议大家多看看webpack官方文档,详细了解各个配置项的含义。就算想不起来,稍微有点印象也是最好的。首先我们看一下webpack的整体原理:初始化参数:从配置文件和Shell语句中读取并合并参数,得到最终的参数;开始编译:用上一步得到的参数初始化Compiler对象,并加载所有配置好的Plug-in,执行对象的run方法开始编译;判断入口:根据配置中的入口找到所有的入口文件;编译模块:从入口文件开始,调用所有配置的Loader来编译模块,然后找出模块的依赖模块,然后递归这一步,直到入口依赖的所有文件都在这一步处理完;完成模块编译:在第4步使用Loader翻译完所有模块后,每个模块翻译后的最终内容和它们之间的依赖关系;outputresources:根据入口和模块之间的依赖关系,将包含多个模块的每个Chunk组装起来,然后将每个Chunk转换成一个单独的文件,添加到输出列表中。这一步是修改输出内容的最后机会;输出完成:确定输出内容后,根据配置确定输出路径和文件名,将文件内容写入文件系统。那么我们再来看看webpack中plugin的原理。在使用htmlWebpackPluin的过程中,我们发现打包后的index.html文件被js引用了两次。因为知道plugin的原理,所以手写了一个。webpack的插件架构主要是基于Tapable实现的,专注于事件的广播和操作。在webpack的编译过程中,会广播很多事件。插件可以自己监听这些事件,在相应的时间webpack执行的时候做一些操作,然后插件也可以广播事件。下面是具体API的实现。webpack中有一个complier对象,代表webpack实例。有特定的编译参数。还有一个代表这次编译的complation,里面有打包好的文件等信息。绑定插件并应用于编译器。在回调函数中传递编译对象。插件:[function(){this.plugin('done',(stats)=>{stats.toJson(true).chunks.filter(c=>c.entry).forEach(c=>{letfileContent=fs.readFileSync((path.join(BUILD_PATH,'views/main.pug'))).toString('utf-8')fs.writeFileSync(path.join(BUILD_PATH,'views/main.pug'),文件内容。replace(/webpack\-bundle.*src="(.*)"/g,(match,p1)=>{returnmatch.replace(p1,PUBLIC_PATH+c.files[0])}))})})}]常见问题分析webpack配置遇到的问题css-loader中importLoaders=1参数的问题问题是在加载的css文件中引入了一个css文件。虽然可以导入到最终的html中,但是导入的css并没有经过postcss处理,添加这个可以解决Mac平台和Windows平台不同导致的问题//配置入口选项时:entry:{main:__dirname+'/src/index.js'}///Constpath=require('path');constentryPath=path.resolve(__dirname,'/src/index.js');entry:{main:entryPath}不能满足业务需求,自定义plugin的过程上面说到提高webpack构建速度的问题缩小了查找文件的范围,在loader中使用了exclude和include。在reslove中使用module,这个可以在需要的时候指定存放第三方模块的路径。通过使用动态链接库,使用插件DllPlugin,可以将各个动态链接库文件一个一个打包。原因是包含大量复用模块的动态链接库只需要编译一次,动态链接库包含的模块在后续的构建过程中不会重新编译,而是直接使用动态链接中的代码图书馆。启用打包编译多进程运行在Node.js上的webpack是单线程模型,也就是说webpack需要处理的任务需要一个一个的完成,不能多个事情一起做。使用插件HappyPack,webpack中最耗时的步骤就是loader步骤。HappyPack将任务分成多个子进程并发执行。子流程处理完成后,将结果发送给主流程。提取公共代码使用CommonsChunkPlugin插件提取公共代码。你用的什么插件?WebpackPlugin用于自动将js和css文件添加到html文件中。CommonsChunkPlugin可以封装代码的公共部分(听说4.0已经不用了)。HappyPack支持多进程加速打包。