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

带你了解webpack

时间:2023-04-05 18:32:57 HTML5

1。前端工程项目打包历史跳过前端工程之前的时代1.半自动执行脚本压缩合并文件自从xmlhttprequest被挖掘出来,网页可以和服务器通信,js可以做什么越来越多,文件体积越来越大,相互引用越来越多。但是,上网速度只有几兆带宽。所以我觉得js文件要狠狠压缩,能合并的还是结合主要的js压缩工具:JSMin简单易用,灵活,对不同语言和环境的支持很好。一般配合不同的环境和语言使用雅虎推出的命令行YUICompressor来执行压缩。有JAVA版和.NET版,两个环境需要配合UglifyJS是基于nodejs的,压缩策略比较安全,所以不会对源码做大的修改。ClosureCompilerProducedbyGoogle我的理解压缩主要是做局部变量命名简化,空白/换行/注释消除,自动优化简化语法等。在用es6语法写的js使用压缩工具的压缩测试对比中:UglifyJS有一个压缩率高,并能自动格式化和优化代码。所以渗透率很高。现在也是YUI压缩器的主流工具。优点是压缩策略是安全的。与UglifyJS相比,自动代码优化的程度更加保守。ClosureCompiler的Advanced模式直接破坏了代码的结构,bug较多。压缩,但是当同时引用a文件和b文件时,使用c文件方式时,如果c文件分别与a和b合并,只会有两个文件。合并就这样开始了。一般通过在windows上使用bat脚本或者在mac/linux上使用shell脚本来决定合并哪些文件,使用什么工具压缩,如何压缩进度:解决一般网速较慢时网页加载资源慢的问题当时代码混淆不容易被盗的问题:项目工程中的相互依赖变得很复杂,合并后的文件中可能会有很多无用的代码,命名什么的完全有可能一不小心就冲突了,可能一层层依赖,不好维护。所以先解决js相互依赖的问题1.探究js依赖的规范CommonJS规范解决了js模块依赖的问题,代表当前模块,有一些指定的默认属性module.exports属性:初始值为空对象{},这个变量暴露了定义的变量和方法exports变量:Node为每个模块提供了一个exports变量,指向module.出口。至于两者的区别,你不用懂。你通常使用module.exportsrequire来引用:在这里使用module.exports定义的变量/方法。注意:是同步的。由于CommonJS提供了模块化的思想,所以它已经在服务器端。(nodejs)炫耀。那么在浏览器中可以吗?浏览器不兼容CommonJS的原因是缺少四个NodeJs环境变量:moduleexportsrequireglobal,所以你只需要提供这几个环境变量即可。Browserify就是这样做的。Browserify是目前最常用的CommonJS格式转换工具。Browserify的核心思想是把模块暴露的模块放到一个数组中。需要时,根据模块id找到对应的模块并执行。简而言之,就是给上面缺失的变量。写成可执行的es5攻略,是不是可以在浏览器上愉快的使用CommonJS呢?CommoJS以同步require的方式获取js模块,在浏览器上会阻塞主线程。页面可能会因为加载js而卡住,这肯定是不能容忍的,于是AMD(AsynchronousModuleDefinition)诞生了。AMD也使用require()语句来加载模块,但是需要传递两个参数require([module],callback)。是的,回调的想法。AMD规范(RequireJS)的简单介绍解决了两个问题:(1)实现js文件的异步加载,避免网页丢失响应(2)管理模块之间的依赖关系,方便代码编写和维护模块必须采用特定的define()函数在加载前定义非AMD第三方库。使用require.config()来定义固有特性。CMD规范和AMD类似,具体实现是seajs。没用过,应该差不多吧,哈哈哈2.HTML/css模块化规范less,sass,styluscss预处理器简化css语法ejs,jade等html模板语法这些真是前端狗的福音,话不多说,css-next来了,继续啃。这样html/css/js就有了适合自动构建的扩展结构。但是此时写一个命令来构建这些依赖太长太复杂,所以打包工具开始流行:3.Grunt/Gulp流处理构建工具让前端构建变得更简单。Grunt写起来简单,插件也很多。Gulp更高效、扩展性更强nodejs与这两个大佬合作,自动化构建web项目。使用起来非常酷vargulp=require('gulp')varnodemon=require('gulp-nodemon')varbrowserSync=require('browser-sync').create()gulp.task('nodemon',function(cb){varstarted=falsereturnnodemon({script:'mswadmin.js',ext:'js',env:{'NODE_ENV':'default'}}).on('start',function(){if(!started){cb();started=true;}})});gulp.task('serve',function(){browserSync.init({proxy:'http://10.3.10.27:18282',浏览器:'chrome',端口:18282})gulp.watch('static/**/*.+(scss|jade|ls)',['inject']).on('change',browserSync.reload);})gulp.task('default',['nodemon','serve']);以上是使用nodemon监控本地服务+watch更新配置的火爆代码。可以看出,任务是以流任务的形式一个一个执行的。也很好用2.SPA(Single-pageapplication)自带js对应的AMD模块,然后AMD模块将对应的html渲染到容器中,让网页不再是传统的文档页面.相反,它更像是一个完整的程序。一个主入口,js完成的前端路由,AMD模块完成页面的重新渲染。这个SPA虽然做出来了,但是有很多小问题:很多成熟的第三方库不支持AMD规范,引用麻烦。RequireJS在加载html依赖时,html中的img路径必须使用绝对路径,并且只能一次全部加载。将css文件分模块打包js文件时,配置公共依赖比较困难。最重要的是,AMD/CMDCommonJS规范太多,很多第三方库没有为规范付出足够的代价。..而且ES6规范要普及了,你不需要吗???3.webpack来救你首先,webpack是一个静态模块打包器(bundler),而grunt/gulp是一个流任务执行器。区分两者可以用grunt-webpack来说明:可以使用webpack或者webpack-dev-server作为任务(task)来执行webpack为什么好用:webpack可以提供ES6的import/export出来该盒子还支持CommonJSCMD/AMD模块规范。准备好使用这两点是我认为最突出的一点。详细对比请参考对比浏览器环境。如果你使用ES6规范,你应该不想使用其他的webpack。工作步骤如下:从入口文件开始递归构建依赖图。将所有文件转换为模块函数。根据依赖关系,将模块功能按照配置文件分组打包成若干个bundle。通过script标签将打包好的bundle注入HTML,通过manifest文件管理bundle文件的运行和加载。打包规则为:一个入口文件对应一个包。该包包括入口文件模块及其依赖模块。按需加载或需要单独加载的模块单独打包到其他bundle中。除了这些bundle,还有一个特别重要的bundle,就是manifest.bundle.js文件,即webpackBootstrap。这个manifest文件首先被加载,负责解析webpack打包的其他bundle文件,使其按需加载和执行。无论您选择哪种模块语法,那些import或require语句现在都已转换为指向模块标识符的webpack_require方法。通过使用清单中的数据,运行时将能够查询模块标识符并检索其背后的相应模块。webpack如何入门虽然网上有很多十分钟入门webpack的教程。但是还是推荐看一下官方的webpack指南。个人认为你应该注意指南中的细节:webpack不会更改除import和export语句之外的部分代码。如果您正在使用其他ES2015功能,请确保您在webpack的加载器系统中使用了Babel或Bublé等转译器。npm脚本在运行时可以默认使用npx命令。应合理使用sourcemap。注意webpack-dev-middleware,配合Express用于服务端渲染。HMR(ModuleHotReplacement)一般使用你选择的框架自带的loader(vue-loader),使用UglifyJsPlugin插件自动移除JavaScript上下文中未引用的代码(dead-code)。在webpack4中使用mode=production代替。为了与SideEffects结合使用,webpack4提供了一种使用SideEffects插件process.env.NODE_ENV==='production'的方法?'[name].[hash].bundle.js':'[name].bundle.js'likethis配置文件中不能使用条件语句,用if/elsesplitChunks优化,webpack4去掉了CommonsChunkPlugin。下面将详细解释动态导入(dynamicimport)优化。chunkFilename确定非入口块的名称。vue中的应用示例是路由延迟加载(vue-lazyload),它会生成一个新的bundle4。webpack优化要点补充说明dynamicimportvue中时间注意事项:webpack可以使用动态import来引用模块,我们使用async/await和dynamicimport来实现。每个动态导入都将打包为一个单独的块。Vue中的一个例子是路由懒加载+babel-plugin-dynamic-import-node的构建方案。使用babel-plugin-dynamic-import-node是因为在开发环境中触发热更新很慢。此插件将所有异步导入更改为需要同步打包以生成文件模块标识符。一般来说,我们在dist中生成了三个bundlemainbundle会随着自身新内容的修改而变化。vendorbundle将随着它自己的module.id被修改而改变。清单包发生变化,因为它当前包含对新模块的引用。但是,我们不希望vendor每次build的时候都生成一个新的hash,毕竟我们要用到缓存。解决方案官方有两个插件,NamedModulesPlugin和HashedModuleIdsPlugin。Vue使用HashedModuleIdsPlugin。相信很多人在从webpack3升级到4的时候都会遇到问题,接下来###5.升级到webpack4的时候你应该明白了。1、零配置的概念主要是利用模式的概念降低配置门槛。在开发模式下,NamedChunksPlugin和NamedModulesPlugin默认开启,方便调试,提供更完整的错误信息和更快的重新编译。在生产模式下,由于提供了splitChunks和minimizer,所以代码会自动拆分,基本零配置。压缩,优化,webpack会自动帮你做Scopehoisting(作用域提升)和Tree-shaking,相当于把一些基础配置作为默认配置。只需要在运行命令行的时候带上mode参数就搞定了####2.部分插件的废除和替换丢弃了replacer(使用optimization属性),将uglifyjs-webpack-pluginminimizer改为压缩和优化CommonsChunkPluginsplitChunks代码拆分。一些新插件:TreeShaking、SideEffects。我还不知道如何使用它--3。新的优化要注意的点extract-text-webpack-plugin->mini-css-extract-plugin它和extract-text-webpack-plugin最大的区别是:它在代码拆分的时候,把原来的css在每个js块包中内联写入的内容将被拆分成单独的css文件。js变得更干净了,css根据optimization.splitChunks的配置进行拆分,自动将css文件拆分成单独的模块,不用担心http资源请求过多。所有[chunkhash]->[contenthash]都是为了解决当css和js文件有依赖时,两者chunkhash相同。这样修改js,在不改css的情况下修改chunkhash页面。它不能被缓存。contenthash可以简单理解为moduleId+content生成的hash相关issue代码的压缩优化在optimization中改为optimization.minimizer.minimizer中,推荐使用optimize-css-assets-webpack-plugin直接配置.但是vue-cli3中的配置是自己配置的。嗯……反正我不想看那些配置,那就干吧~~~4.第三方库和业务代码的单独打包策略上面很多地方都提到了optimization.splitChunksWebpack4。最大的改进是代码拆分块。webpack3是通过CommonsChunkPlugin拆分的。而现在直接丢弃了,怎么办?,跟着。CodeSplitting的开启很简单,使用production模式即可,它会自动开启。并且有一个很好的设置和一个非常合理的配置。如果同时满足以下条件,chunk将被拆分:新的chunk可以被重用,或者模块来自node_modules目录。newchunk大于30Kb(min+gzbeforecompression)按需加载chunk的并发请求数小于等于5页面初始加载时的并发请求数小于等于到3个默认配置。项目使用第三方UI组件库,在main.js入口依赖第三方库。因为在入口处引入,所以会把第三方库打包到app.js中。这样,只要我修改app.js中的其他代码,package的hash就会发生变化。浏览器必须再次缓存app.js。第三个库相当于又被缓存了,这显然不是我们想要的。看一下配置splitChunks:{chunks:"all",cacheGroups:{libs:{name:"chunk-libs",test:/[\\/]node_modules[\\/]/,priority:10,chunks:"initial"//只打包初始依赖的第三方},elementUI:{name:"chunk-elementUI",//单独解包elementUIpriority:20,//权重大于libs和app,否则打包后输入libs或apptest:/[\\/]node_modules[\\/]element-ui[\\/]/},commons:{name:"chunk-commons",test:resolve("src/components"),//你可以自定义和扩展你的规则minChunks:2,//最小分享次数priority:5,reuseExistingChunk:true}}};主要思路是把依赖初始化的第三方封装成一个基础类库,这样的改动很小,全世界都需要从全局通用的router,function中抽出像elementUI这样比较大的改动和小的改动,svgicon,layout布局组件等,直接丢在app.js业务中会经常用到但main.js中没有引入的组件,封装成常用业务但体积比较小。它们直接导入到main.js中并打包到app.js中。其他不常用的组件会根据默认的splitChunks自动设置拆分提醒:代码的拆分一定要结合项目的实际情况。比如你在element中只使用一两个组件,可以根据需要在main.js中加载,然后直接打包到app.js中。所以没有最合理的拆分规则,只有最适合自己的。5.Prefetching/Preloading模块支持Prefetching/Preloading浏览器资源加载优化。核心思想是减少JS下载时间。如果你不能学习它,你就无法学习它。先慢下来。6.最后推荐http://webpack.wuhaolin.cn/