当前位置: 首页 > Web前端 > HTML5

(开篇)模仿《Vue生态》系列___《你是webpack吗?》

时间:2023-04-05 20:37:09 HTML5

(开场)模仿《Vue生态》系列___《你是webpack吗?》这个系列的作者也去深造了一个月了,学习了很多前端相关的视频资料。我觉得目前的知识只是表现出彼此之间的联系很弱,即还不是一个‘系统’。每个知识点我都学会了。两者都会用到,只是有些地方统一的时候不是很清楚。相信很多前端小伙伴都会有同感。例如:1:你知道你经常使用的插件的原理吗??2:能不能自己写一个插件,其他类似功能的插件可以给别人用吗???3:不借助外挂能正常开发吗??4:面试的时候,面试官问你,某些技术的原理,你只能回答“我只是站在巨人的肩膀上吗?”┑( ̄Д ̄)┍为了理解“围绕”的系列知识framework',这次从0开始,和大家一起写一个简单版的vue框架,不仅要写框架,还要写vuex,vue-router,axios,simplewebpack,webpack-loader,webpack-plugin等涉及到的知识点会详细讨论,有没有讨论到位的可以私信继续死。本项目会在github上同步更新。从去年到今年年初,我一直在公司负责面试前端。因此,文章不仅涉及技术,还穿插了我的理解和之前的笔记,以及我在面试中遇到的一些问题。毕竟再过一两个月我就要结束找工作的“闭关”了,所以面试方面我也会讨论一下。大家可以分享相关的知识和问题一起交流,一起学习,一起进步,早日实现自我价值!!一、前端与webpack(本工程师基于webpack4)webpack现在可以说是前端必备技能了。如果有人告诉你,看一看文档就不需要学习了,那就是在害你。Webpack是一项需要熟悉的技术。你必须在不看信息的情况下手写出最基本的结构。现在框架已经帮我们集成了开发环境。从另一方面来说,温水煮青蛙可以麻痹我们的神经。“只要你会用”并不适合webpack。这个技术可以帮助我们更好的理解前端岗位的定义。工欲善其事,必先利其器,那么本期将从webpack的配置入手!需求分析1:本次实现的简单框架暂定名为'C',开发使用class的形式,所以需要支持es62:可以加载css文件,因为有了style,写代码就有趣了3:热更新4:差异化生产环境和开发环境就是巩固webpack优化的知识库--逐行分析!1:创建一个dist文件夹存放打包后的文件2:创建一个src文件夹存放开发信息3:src中的Index.jsMain导出文件4:安装依赖npminstallwebpackwebpack-cli-D能不能敲最基本的代码下面不看资料?做的东西exactly.constpath=require('path');module.exports={mode:'development',entry:{main:'./src/index.js'},output:{filename:'[name].js',path:path.resolve(__dirname,'../dist')}}知识点总结(致命知识点...)1:Pathnode的原生模块。Resolve与它一起出现join两种方法join:Windows下的文件路径分隔符使用“”,Linux下的文件路径分隔符使用“/”,path.join()方法使用平台特定的分隔符将所有给定的路径段连接在一起,并将生成的路径片段规范化为路径长度为零将被忽略。如果连接的路径字符串是零长度字符串,则返回“.”,表示当前工作目录。onsole.log(path.join('a','b','c','..','d'))打印a/b/d拼接在一起,..killc;resolve:方法将路径或一系列路径片段解析为绝对路径,如果没有传入路径片段,则path.resolve()将返回当前工作目录的“绝对路径”。console.log(path.resolve('a','b','c'))/Users/lulu/web/cc_vue/a/b/c准确到项目2:module.exports节点的模块导出方式,为什么它用'。'链接,而我们用的es6是''空格,例如:exportdefault原因:学过node的朋友会很好理解,node可以随时读取文件,而module只是一个变量,exports是一个属性模块。每个文件被读取后,用户要输出的文件被挂载到这个对象上,所以它使用'.'。方法,实际上是在操作对象。es6的语法在浏览器上是无法实现的,需要编译后执行。它使用关键字模式。比如我写一个打包插件,对exportdefault的语法进行打包,我需要先解析语法树,然后把文件中的绝对路径转换成key,内容是一个闭包的值(这个后面会做),所以es6的引入方法是同步的,不能写在任何地方;三:mode:webpack新增的mode属性第一个。none不使用webpack自带的模式Second。development:开发模式1.不压缩2.不摇树(为什么开发环境不'摇树'?原因是去掉冗余代码,调试时就找不到准确的段落;)3.有完善的错误提示4.可以设置一个完整的source-map//添加如下两个插件:[//在开启HMR的情况下使用这个插件时,会显示模块的相对路径,而不是id的文件。newwebpack.NamedModulesPlugin(),//改变全局环境变量newwebpack.DefinePlugin({"process.env.NODE_ENV":JSON.stringify("development")}),]Third.生产在线模式//自动添加插件:[//压缩js代码newUglifyJsPlugin(/*...*/),//设置环境变量newwebpack.DefinePlugin({"process.env.NODE_ENV":JSON.stringify("production")}),//过去webpack打包的权衡之一是将bundle中的每个模块单独打包到闭包中。这些包装器函数使您的JavaScript在浏览器中的处理速度变慢。相比之下,这个插件可以将所有模块提升或预编译到一个闭包中,从而提高代码在浏览器中的执行速度。newwebpack.optimize.ModuleConcatenationPlugin(),//使用NoEmitOnErrorsPlugin在编译错误时跳过输出阶段。这确保输出资源不会包含错误。对于所有资源,统计信息(stat)发出的标志都是假的。newwebpack.NoEmitOnErrorsPlugin()]四:entry直接写字符串entry:./xx/index这时候默认名字是mainmulti-entryfilewritearray[./xx1/index,./xx1/index]对象,这也是官方推荐的写法,每个entry定义一个名字,使用entrywithpackagedoutput:{main:'./src/index.js',beas:'./src/base.js'}五:output这个比较简单//这里可以自定义名字,'写死'就可以了//下面这个方法的意思是上面入口的名字是什么,这里是什么//一般多入口包装写成这样thisfilename:'[name].js',//这种形式结合上面的知识点肯定没问题,//__dirname:当前文件所在的文件夹路径:path.resolve(__dirname,'../dist')看完这些你感觉如何???虽然只有几行代码,但是你还需要砸一下babel相关的npminstallbabel-loader-Dmodule。模块中的规则选项专用于加载程序。钥匙只有一个,也是用对象的形式写的。估计以后会有什么动作。module:{rules:[{test:/.js$/,exclude:/node_modules/,loader:'babel-loader?cacheDirectory=true'}]}test是指定的匹配规则。后面有机会再说说排除不处理文件的正则相关的技巧。也就是说,所有的依赖都不翻译,如果不加上这句话加载器会很慢,这是匹配到的文件内容的具体处理方式。以上写法是官网推荐的,默认值为false。设置后,指定的目录将用于缓存加载程序的执行结果。后续的webpackbuild会尝试读取缓存,避免每次执行时可能产生高性能消耗的Babel重新编译过程。babel-loader是做什么的?看完他的源码,他就是leader,负责安排专人进行编译工作,他只负责调度和输出。核心员工“@babel/core”npminstall@babel/core-D和他的命名公式7.x开始标准化,有些人可能已经看到'-'链接,这是一个早期版本,因为它只是一个执行特定动作的模块,所以需要以@babel开头,其实具体的工作都是由这个模块完成的,所以你只需要加载babel-loader是没有用的。其实babel团队的设计是符合设计模式的。Webpack还分离了webpack-cli。现在很多插件都不是一个文件。babelrcwebpack中的配置项太多,如果全部集中在一个文件中,不符合设计原则。这个很常见,配置项很多,会单独提取配置,babelrc(和.babelrc.js/package.json#babel)文件名可以是@babel/preset-env来指定目标需求?npminstall@babel/preset-env-Dbabel转换js代码的功能其实可以很详细,比如有些人需要全部转换才能兼容ie7语法,我一般转换成这样兼容最新5个版本的Chrome,无需过度转换造成性能损失。需要在.babelrc文件中设置,在presets选项下指定,指定我要解析到什么程度。有个对照表,结合配置项计算交叉配置的“presets”:[["@babel/preset-env",{//写1个"targets":{//1%以上的浏览器ofusers最近两个版本"browsers":[">1%","last2versions"]}//Writing2"targets":{"chrome":"58","ie":"11"}}]],这种形式:无需任何配置,preset中包含的插件将支持所有最新的JavaScript(ES2015、ES2016等)功能"presets":["@babel/preset-env"],官方维护的类型@babel/preset-env@babel/preset-flow@babel/preset-react@babel/preset-typescriptStage0-Idea(Strawman):只是一个想法,可能会有一个Babel插件。Stage1-Proposal:这值得跟进。Stage2-Draft:初始规范。Stage3-Candidate:完成规范和初始浏览器实现。Stage4-Finished:将添加到下一个年度版本发布中。preset-es2015等都换成了@babel/preset-env,我们只是在babel7版本上做了箭头函数的改造,但是没有像promise这样的实例方法是的,babel分工很明确,上面的配置而已转换霸气的polyfill运行时库,所以如果save!!!!npminstall--save@babel/polyfill这个库会模拟一个完整的ES2015+环境。使用就是在相应的页面上取require。为什么说他霸道?这家伙是个硬汉,一脑子就把所有的配置都给注入了。有了它,打包后的体积吓人,但他也是最全面的。结果我用不到的功能他都写完了,非常没有必要,所以babel给了配置项,只能注入我们用到的类和方法,这样体积会减少很多。还是得按‘要求’付费才行。"presets":[["@babel/preset-env",{"useBuiltIns":"usage"//使用polyfill时只加载使用过的方法}]]他还有一个致命的缺点就是污染了整个世界。比如我开发一个插件给你用,我会把你的全局变量全部改成最新版本。开发插件的原则是尽量不触及用户数据。他的另一个版本很烂,所以开发插件babel提供了如下解决方法@babel/plugin-transform-runtimeplugin-transform-runtime默认已经包含了@babel/polyfill,所以不需要单独引入。npminstall@babel/plugin-transform-runtime-D也是赋值,具体需要安装的代码注入从他的文件中取出来。npminstall--save@babel/runtime避免多次编译辅助函数:Babel转过来的代码如果想实现和原代码一样的功能,需要使用一些辅助函数。@babel/runtime包声明了所有需要使用的辅助函数,@babel/plugin-transform-runtime的作用也就是所有需要辅助函数的文件,依赖@babel/runtime包不会污染全局变量。多次使用只会包装一次。依赖统一的按需导入,没有重复导入,没有冗余导入//缺点是不支持实例化Array.includes(x)的方法,无法进行改造,因为如果这样实现,会污染整个世界。如果使用的API用得不多,那么transform-runtime引入的polyfill包会比non-transform-runtime引入的大。这个应该在.babelrc文件夹,在plugins选项里配置“plugins”:[["@babel/plugin-transform-runtime",{"absoluteRuntime":false,//如果配置为2,false不需要to//需要安装@babel/runtime-corejs2//不需要安装@babel/runtime//作用:promise代码变成一个自变量_promise,不会影响全局的Promise。"corejs":2,//默认为true,写出来让大家知道"regenerator":true,//切换generator函数是否转换为使用不会污染全局作用域的regeneratorruntime。}]]以上配置完成后,就可以正常播放es6了。以上这些你都看完了,还怕以后别人问你这方面的知识吗??开头也提到了css样式,有一个很好的Modeling,代码写的也很愉快module:{//只有一个key,也写成value。估计以后会有一些动作。rules:[{test:/.(css|sass|scss|less)$/,use:['style-loader','css-loader','postcss-loader']}]}配置类似,让我详细解释每个装载机。style-loader:使用