当前位置: 首页 > Web前端 > vue.js

4.Webpack详解

时间:2023-03-31 16:16:14 vue.js

.title{颜色:绿色;}webpack基本认识webpackwebpack是现代JavaScript应用的静态模块打包工具。涉及到两个概念:模块和打包模块项目通过模块化开发完成后,需要对模块之间的各种依赖关系进行处理和集成打包。webpack的核心之一就是让我们可以进行模块化的开发,它会帮助我们处理好模块之间的依赖关系。而且不仅仅是JavaScript文件,我们的CSS、图像、json文件等都可以作为webpack中的模块。这就是webpack中模块化的概念。打包(bundle)就是将webpack中的各种资源模块打包组合成一个或多个包(Bundle)。并且在打包的过程中,还可以对资源进行处理,比如图片压缩、scss转css、ES6语法转ES5语法、TypeScript转JavaScript等等。不过好像grunt/gulp也可以帮我们完成打包操作。它们之间有什么区别?与grunt/gulp的比较grunt/gulp的核心是Task。我们可以配置一系列任务,定义任务要处理的任务(比如ES6、ts转换、图片压缩、scss转css)。然后让grunt/gulp依次执行这些任务,把整个过程自动化。所以grunt/gulp也被称为前端自动化任务管理工具。我们来看一个gulp任务:下面的任务是将src下的所有js文件转成ES5语法。最后输出到dist文件夹。constgu1p=requireC('gulp');constbabe1=require('gu1p-babe1');gulp.task('js',()=>gulp.src('src/*.js').pipe(babe1({presets:['es2015']})).pipe(gulp.dest('dist')));什么时候使用grunt/gulp?如果你的工程模块依赖非常简单,连模块化的概念都用不上。只需使用grunt/gulp进行简单的合并和压缩。但是如果整个项目采用模块化管理,相互依赖性很强,我们可以使用更强大的webpack。那么,grunt/gulp和webpack有什么区别呢?grunt/gulp更强调前端流程的自动化,模块化并不是其核心。webpack更强调模块化开发管理,文件压缩合并、预处理等功能是它的附属功能。webpack的安装要安装webpack,首先需要安装Node.js。Node.js自带包管理工具npm。cnpminstallwebpack--save-dev//--save-dev是开发依赖,项目打包后不需要使用。直接在终端执行webpack命令,使用全局安装的webpack。当在包含webpack命令的package.json中定义脚本时,将使用本地webpack。webpack起始文件及文件夹分析:dist文件夹:用于存放后面打包的文件src文件夹:用于存放我们编写的源文件-----main.js项目的入口文件。具体内容详见下文wb。index.html:浏览器打开时显示的首页htmlpackage.json:由npminit生成,npm包管理的文件(暂时不用,以后会用到)js文件打包webpacksrc/main.jsdist/bundle使用打包文件打包.js后,dist文件下会生成一个bundle.js文件。bundle.js文件是webpack处理项目直接文件依赖后生成的js文件。我们只需要在index.html中导入这个js文件就可以配置webpack,在本地安装webpack,因为一个项目往往依赖于特定的webpack版本,全局版本可能和本项目的webpack版本不一致,导出打包有问题。所以通常一个项目都有自己的partialwebpack。//安装并指定你需要的版本cnpminstallwebpack@3.6.0--save-dev//启动webpack打包node_modules/.bin/webpackpackage.json定义启动我们可以在package的scripts中定义自己的执行脚本。JSON。{"name":"meetwebpack","version":"1.0.0","description":"","main":'index.js',"scripts":{"build":"'webpack"},"author":"","license":"ISC","devDependencies":{"webpack":"^3.6.0"}}package.json中的脚本执行时,会遵循一定的inorder找到命令对应的位置。首先,它会在本地的node_modules/.bin路径下寻找对应的命令。如果没有找到,它将在全局环境变量中寻找它。//执行构建命令cnpmrunbuild搭建一个本地服务器webpack提供了一个可选的本地开发服务器,这个本地服务器是基于node.结果之后。npminstall--save-devwebpack-dev-server@2.9.1devserver也是webpack中的一个选项。该选项本身可以设置以下属性:`contentBase`:哪个文件夹提供本地服务,默认是根文件夹,这里需要填写./dist`port`:端口号`inline`:实时页面刷新`historyApiFallback`:在SPA页面中,依赖HTML5history模式devServer:{contentBase:'./dist',inline:true}可以配置另外的scripts:--open参数表示直接打开浏览器"scripts":{"build":"webpack","dev":"webpack-dev-server--open"},如果每次进入和退出所有使用webpack的命令都需要把进入和退出写成参数。有一种方法可以将这两个参数写入配置中,并在运行时直接读取它们。创建一个webpack.config.js文件constpath=require('path')module.exports={//entry:可以是字符串/数组/对象,这里我们只有一个entry,所以只写一个字符串entry:'./src/main.js',//导出:通常是一个对象,它至少包含两个重要的属性,路径和文件名output:{path:path.resolve(__dirname,'dist'),//注意:路径通常是绝对路径文件名:'bundle.js'}}加载器用法什么是加载器?Loader是webpack中一个非常核心的概念。在开发中,我们不仅有基本的js代码处理,还需要加载css和图片,还包括ES6到ES5代码的一些高级转换,TypeScript到ES5代码的转换,scss和less到css的转换,.jsx、.vue文件转换成js文件等。对于webpack自身的能力,不支持这些转换。此时需要为webpack扩展相应的loader。Loader使用流程:Step1:通过npm安装要使用的loaderStep2:在webpack.config.js中modules关键字下配置大多数loader都可以在webpack官网找到,学习对应的用法。loader的执行顺序是从下到上,从右到左。CSS文件处理需要两个加载器:css-loader和style-loader。css-loader负责加载css文件;style-loader负责将特定于css的样式嵌入到文档中。安装cnpminstall--save-devcss-loaderstyle-loaderwebpack.config.js配置constpath=require('path');module.exports={mode:'development',entry:{main:'./src/index.js'},输出:{文件名:'bundle.js',路径:path.resolve(__dirname,'dist')},模块:{规则:[{test:/\.css$/,使用:['style-loader','css-loader'],}]},}因为webpack是按照从右到左的顺序读取使用的loader。所以style-loader需要放在css-loader之前。less/scss文件处理需要安装less和less-loader。rules:[{test:/\.less$/,use:[{loader:"style-loader"//从JS字符串创建样式节点},{loader:"css-loader"//将CSS翻译成CommonJS},{loader:"less-loader"//将Less编译成CSS}]}]图片文件处理url-loader,file-loader当加载的图片小于限制时,会把图片编译成base64字符串形式。当加载图片大于限制时,需要使用file-loader模块加载。修改文件名。当图片大于限制时,使用file-loader默认将图片打包重命名为32位哈希值,放入dist文件夹。{test:/\.(png|jpg|gif|jpeg)$/,use:[{loader:'url-loader',options:{//当加载的图片小于限制时,会编译图片转换为base64字符串格式。//当加载的图片大于限制时,需要使用file-loader模块加载。limit:13000,//[ext]:表示原文件名的后缀。[名称]:表示原始文件名。[hash:8]:为了防止图片名称冲突,仍然使用hash,但我们只保留8位的名称:'img/[name].[hash:8].[ext]'},}]},我们发现图片没有显示出来,这是因为图片使用的路径不对。默认情况下,webpack会将生成的路径直接返回给用户。但是我们整个程序是打包在dist文件夹下的,所以这里需要在路径下再添加一个dist/。output:{path:path.resolve(__dirname,'dist'),filename:'bundle.js',publicPath:'dist/'},babel的使用如果想把ES6语法转成ES5,那么需要使用通天塔。在webpack中,我们可以直接使用babel对应的loader。npminstall--save-devbabel-loader@7babel-corebabel-preset-es2015配置webpack.config.js文件{test:/\.js$/,//exclude:exclude//include:includeexclude:/(node_modules|bower_components)/,use:{loader:'babel-loader',options:{presets:['es2015']}}}Theuseofpluginplugin的意思是插件,通常用于对一个已有的结构进行扩展。webpack中的插件是对webpack现有功能的各种扩展,比如打包优化、文件压缩等。loader和plugin的区别loader主要是用来转换某些类型的模块,它是一个转换器。Plugin即插件,是webpack本身的扩展,是一个扩展器。插件使用流程:第一步:通过npm安装需要使用的插件(部分webpack内置插件不需要安装)第二步:在webpack.config.js中的plugins中配置插件。添加版权的PluginBannerPlugin属于webpack自带的插件。constpath=require('path')constwebpack=require('webpack')module.exports={...plugins:[newwebpack.BannerPlugin('最终版权属于??aaa'),],}那个插件packshtml实际发布项目时,需要将index.html文件打包到dist文件夹中。这时候就可以使用HtmlWebpackPlugin插件了。HtmlWebpackPlugin插件可以为我们做这些事情:自动生成一个index.html文件(可以指定模板生成),自动通过script标签将打包后的js文件插入到body中。npminstallhtml-webpack-plugin--save-devconstpath=require('path')constHtmlWebpackPlugin=require('html-webpack-plugin')module.exports={...插件:[newHtmlWebpackPlugin({模板:'index.html'//指定生成Html文件时使用的模板。}),],}另外,我们需要删除之前在输出中添加的publicPath属性,否则插入的script标签中的src可能有问题。CleanWebpackPluginCleanWebpackPlugin会在打包前删除指定目录下的内容。npminstallclean-webpack-plugin-Dwebpack.config.jsconst{CleanWebpackPlugin}=require('clean-webpack-plugin');//添加{}module.exports={...plugins:[newHtmlWebpackPlugin({template:'src/index.html'}),newCleanWebpackPlugin()//不能添加参数。],}性能优化优化构建速度优化babel-loader优化Loader的文件搜索范围缓存babel编译文件module.exports={module:{rules:[{test:/\.js$/,//js文件使用babelloader:'babel-loader?cacheDirectory=ture',//下次只需要编译修改后的代码文件include:[resolve('src')],//只在src文件夹中搜索exclude:/node_modules/,//不会搜索的路径}]}}ParallelUglifyPlugin使用ParallelUglifyPlugin打开多进程压缩JS文件happyPack允许loader处理多进程文件,借助缓存机制,重建时可以更快constpath=require('path')constHappyPack=require('happypack');module.exports={...newHappyPack({id:'jsx',threads:4,loaders:['babel-loader']}),newHappyPack({id:'styles',threads:2,loaders:['style-loader','css-loader','less-loader']})}DllPlugin和DllReferencePluginDllPlugin可以打包特定的类ss库提前然后导入。这种方法可以大大减少打包类库的次数。只有当类库更新时,才需要重新打包,同时也实现了将公共代码分离到单独文件中的优化方案。webpack自带的库。使用DllPlugin减少基础模块的编译次数。使用DllReferencePluhin将依赖文件引入到项目中。constpath=require('path')constwebpack=require('webpack')module.exports={...newwebpack.DllPlugin({name:'[name]-[hash]',//name必须是同output.libraryconsistentcontext:__dirname,//该属性需要和DllReferencePluginpath一致:path.join(__dirname,'dist','[name]-mainfest.json')}),newwebpack.DllReferencePlugin({context:__dirname,mainfest:require('./dist/vendor-mainfest.json')})}IgnorePluginnoParse优化开发体验使用webpack监听文件的自动刷新,通过--watch参数启动webpack;在配置文件中设置watch:true。DevServer刷新浏览器DevServer刷新浏览器有两种方式:在网页中注入代理客户端代码,通过客户端加载一个iframe到网页中发起刷新,刷新iframe实现刷新效果。需要重启服务器才能生效。开启方式:webpack-dev-server--hotuseHotModuleReplacementPluginconstpath=require('path')constwebpack=require('webpack')module.exports={...newwebpack.HotModuleReplacementPlugin()}优化输出代码使用生产环境小图片base64编码bundle加hash使用CDN提取公改代码懒加载配置webpack中的Vueel和template区别在之前的Vue实例中,我们在index.html中定义了el属性用于与#app绑定,这样Vue然后实例可以管理它的内容。这里,我们可以删除div元素中的{{message}}内容,只保留一个id为div的基本元素。但是如果我还想在里面显示{{message}}的内容,怎么办呢?我们可以再定义一个模板属性,代码如下:newVue({el:'#app',template:'{{message}}

',data:{message:'coderwhy'}})el和template是什么关系?el用于指定Vue要管理的DOM,可以帮助解析其中的指令、事件监听等。并且如果在vue实例中同时指定了template,则模板template的内容会替换挂载的对应el模板。这样做之后,我们以后的开发就不需要再去操作index.html了。我们只需要在模板中写上相应的标签,后面就可以提取模板模板中的内容了。会分模板、脚本、样式三部分来写,结构变得非常清晰。.vue文件封装处理main.js//使用Vue开发importVuefrom'vue'importAppfrom'./vue/App.vue'newVue({el:'#app',template:'',components:{App}})vue-->App.vue.title{颜色:绿色;}安装vue、vue-loader和vue-template-compiler进行处理。npminstallvue-loadervue-template-compiler--save-devcnpminstallvue--savemodule:{rules:[{test:/\.vue$/,use:['vue-loader']}]},//解决runtime-onlyversionofVueerrorresolve:{//alias:aliasextensions:['.js','.css','.vue'],alias:{'vue$':'vue/dist/vue.esm.js'}}