Vue2:webpack
打包工具:项目工程化工具
什么是webpack?(面试题)
webpack 是代码编译工具,有入口、出口、loader 和插件。webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。
webpack 是一个打包模块化 javascript 的工具,在webpack 里一切文件皆模块,通过 loader 转换文件,通过 plugin 注入钩子,最后输出由多个模块组合成的文件,webpack 专注构建模块化项目; webpack 可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript 模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用
还有哪些常见的打包工具?
1、grunt 与 gulp
2、snowpack
特点:速度快
3、parcel
https://www.parceljs.cn/getting_started.html
4、esbuild
5、rollup
6、vite
7、webpack
https://webpack.docschina.org/
webpack 与 grunt、gulp 的不同?
1、三者之间的区别 三者都是前端构建工具,grunt 和 gulp 在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用 gulp 来处理,比如单独打包CSS文件等
1.1grunt 和 gulp 是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据,整条链式操作构成了一个任务,多个任务就构成了整个 web 的构建流程。
1.2webpack 是基于入口的。webpack 会自动地递归解析入口所需要加载的所有资源文件,然后用不同的 Loader 来处理不同的文件,用 Plugin 来扩展webpack功能。
2、构建思路的区别
2.1gulp 和 grunt 需要开发者将整个前端构建过程拆分成多个Task
,并合理控制所有Task
的调用关系
2.2webpack 需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader 做何种解析和加工
3、 从知识背景区别
3.1gulp 更像后端开发者的思路,需要对于整个流程了如指掌
3.2webpack 更倾向于前端开发者的思路
核心概念
-
-
打包完成以后的项目文件输出到哪里
-
打包的时候,解析某些类型的文件 需要按照语法去解析编码,不同类型的文件需求不同的加载器
-
具有某类功能的工具
-
可以在配置文件中设定开发模式,用于未来开发脚手架的配置
-
低版本浏览器不能用
-
Webpack 5 运行于 Node.js v10.13.0+ 的版本。
*这里下载5.0版本
npm install webpack webpack-cli -g//不指定版本,默认下载最新版本,全局安装以后直接使用 mkdir webpack-demo //创建项目文件夹,随意名字同js变量名规则 cd webpack-demo //进入项目文件夹 npm init -y //生成项目配置文件 创建一个webpack.config.js的打包配置文件 代码: module.exports={ 项目入口配置, 项目出口配置, 加载器配置, 插件配置, 开发模式配置, 其他 }
项目入口配置
在webpack.config.js文件内配置
//1.直接配置入口文件 module.exports = { entry: './path/to/my/entry/file.js', //输出时默认为main.js }; //2.配置基础目录,然后配置入口文件 module.exports = { context: __dirname+'/app', entry:"./test.js" //相对于context的路径 }; //3.多入口 module.exports = { context: __dirname + '/app', entry: { a: './test.js', //输出时默认为a.js b: './test2.js', //输出时默认为b.js test3: './test3.js' //输出时默认为test3.js } } //4.多入口 module.exports = { context: __dirname + '/app', entry: ['./test.js','./test2.js', './test3.js'] //输出时默认为main.js,而且全部打包在一起 } 总结:如果传入一个字符串或字符串数组,chunk 会被命名为 main。如果传入一个对象,则每个属性的键(key)会是 chunk 的名称,该属性的值描述了 chunk 的入口点。 //5.入口配置 module.exports = { context: __dirname + '/app', entry: { //输出时默认为a.js a: './test.js', //输出时默认为pages文件夹下的b.js b: { import: './test2.js', filename: 'pages/[name].js' }, //输出时默认为pages文件夹下的c666.js c: { import: './test3.js', filename: 'pages/[name]666.js' } //输出时默认为pages文件夹下的d+哈希值+666.js d: { import: './test4.js', filename: 'pages/[name][hash]666.js' } //输出时默认为pages文件夹下的e+3位哈希值+666.js e: { import: './test5.js', filename: 'pages/[name][hash:3]666.js' } } }; 总结: 1.[name]代表entry的当前属性名 [hash]代表哈希值 2.配置对象除了import和filename还有很多,比如做加载相关的asyncChunks,自行查官网了解
名字解释 bundle,chunk,module 是什么?(面试题)
2、chunk:表示代码块,一个 chunk 可以由多个模块组成
3、bundle:最终打包完成的文件,一般就是和 chunk 一一对应的关系,bundle就是对 chunk 进行编译压缩打包等处理后的产出
项目出口配置
module.exports = { mode: "none", context: __dirname + '/app', // entry:'./test.js', entry: { a: './test.js' }, output: { asyncChunks: true, //创建按需加载的异步 chunk。 path:__dirname+"/dist2",//输出的目录,绝对路径,默认dist // filename: 'bundle.js', //输出的文件名 filename: '[name]-666-[id]bundle[hash:5].js', //输出的文件名,[hash:5]为5位哈希值,[id]为打包的chunk的id,[name]为入口的属性名,缺省则为mian,这几个一定记住 vue和react的css作用域-就是这个几个设计的 // library: 'hqyj',//库名 library: { name: 'MyLibrary', //库名 type: 'var', //配置将库暴露的方式。('var'、'module'、'assign'、'assign-properties'、'this'、'window'、'self'、'global'、'commonjs'、'commonjs2'、'commonjs-module'、'commonjs-static'、'amd'、'amd-require'、'umd'、'umd2'、'jsonp' 以及 'system') }, // libraryTarget: 'umd',//配置如何暴露 library,优先级比library高但是:[请使用 output.library.type 代理,因为我们可能在未来放弃对 output.libraryTarget 的支持。] auxiliaryComment: 'Test Comment', //各种模块化导出技术的统一注释(把type设置为umd) //各种模块化导出技术的分别注释(webpack允许你的项目使用各种模块化技术 它都可以识别并打包) // auxiliaryComment: { // root: 'Root Comment', // commonjs: 'CommonJS Comment', // commonjs2: 'CommonJS2 Comment', // amd: 'AMD Comment', // }, clean: true, // 在生成文件之前清空 output 目录 // clean: { // dry: true, // 小黑窗打印而不是删除应该移除的静态资源 // }, // clean: { // keep: /ignored\/dir\//, // 保留 'ignored/dir' 下的静态资源不删 // // keep(asset) { // // return asset.includes('ignored/dir');//同上 // // }, // }, } };
加载器配置
module.exports={ //加载器配置loader, module:{ rules:[ {test:/\.css$/,use:["style-loader","css-loader"]}//use数组的加载是从后向前解析 ] } }
module: { rules: [ //直接以style标签形式动态写入到页面 {test:/\.css$/,use:["style-loader","css-loader"]}, //项目中引入了以下结尾的文件就会启动file-loader {test:/\.(png|jpg|jpeg|mp4|mp3)$/,use:["file-loader"]}, ] },
3、ts-loader
module: { rules: [ //直接以style标签形式动态写入到页面 // {test:/\.css$/,use:["style-loader","css-loader"]}, { test: /\.css$/, //css生成到css文件中,项目中以<link>形式引入使用 use: [MiniCssExtractPlugin.loader, 'css-loader'] }, {test:/\.(png|jpg|jpeg|mp4|mp3)$/,use:["file-loader"]}, { test: /\.ts$/, use: 'ts-loader' }, ] },
module: { rules: [ //直接以style标签形式动态写入到页面 // {test:/\.css$/,use:["style-loader","css-loader"]}, { test: /\.css$/, //css生成到css文件中,项目中以<link>形式引入使用 use: [MiniCssExtractPlugin.loader, 'css-loader'] }, {test:/\.(png|jpg|jpeg|mp4|mp3)$/,use:["file-loader"]}, { test: /\.ts$/, use: 'ts-loader' }, //exclude:/node_module/ 意思是下载的模块不转码,其他js文件转码 { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], plugins: ['@babel/plugin-proposal-object-rest-spread'] } } } ] },
module: { rules: [ { test: /\.s[ac]ss$/i, use: [ 'style-loader', //不用单独引入 直接运行js代码 动态写入页面 'css-loader', // 将 Sass 编译成 CSS 'sass-loader', ], }, ], },
插件配置
1、
环境准备:
如果未安装 eslint >= 7
,你还需先通过 npm 安装:
npm install eslint --save-dev
插件配置:
const ESLintPlugin = require('eslint-webpack-plugin'); module.exports = { // ... plugins: [new ESLintPlugin(options)], // ... }; //options的参数配置: context:__dirname+"/src" //指定文件根目录 extensions:String|Array[String] //指定需要检查的扩展名.不配置默认为"js" exclude:"node_modules" //指定需要排除的文件及目录。必须是相对于 options.context 的相对路径。 files:String|Array[String] //指定目录、文件或 globs ,必须是相对于 options.context 的相对路径。 如果是目录则递归查找所有匹配 options.extensions 选项的文件。
2、
安装:
npm install --save-dev html-webpack-plugin
配置:
const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: 'index.js', output: { path:__dirname+'/dist', filename: 'bundle.js', }, plugins: [new HtmlWebpackPlugin()], }; //该插件将为你生成一个HTML5 文件, 在 body 中使用 `script` 标签引入你所有 webpack 生成的bundle.js。 //但是每次生成的模板都是新的
开发模式配置
安装:npm install --save-dev webpack webpack-dev-server webpack-cli
配置:
module.exports = { devServer: { //告诉dev-server在服务器启动后打开浏览器。将其设置为true以打开默认浏览器。但是:如果你的电脑有防火墙或者有管理员权限的限制或者电脑很卡 可能不会自定打开浏览器 open: true, //cli中 webpack serve --open //本地服务器监听的端口 port: 8080, //启用热更新,直接使用webpack的热更新模块.就是改了代码自动打包后自定刷新浏览器页面:bug就是同open,记住 卡了就刷新一下不用纠结 hot: true, //指定要使用的主机(localhost|ipv4|ipv6)。如果你想让你的服务器可以被外部访问,像这样指定: //让你同桌访问 然后你改项目代码 他就会刷新 host: '192.168.2.60', //启用gzip压缩 compress: true, //代理配置,这里只是配置,不用写代理服务器的代码(配置好了它帮我们实现) proxy: { '/api': 'http://localhost:7001', }, // proxy: { // '/api': { // target: 'http://localhost:7001', // secure:true,//如果代理的target是https接口,需要配置它 // pathRewrite: { '^/api': '/chongxie' },//请求时重写pathname // }, // }, } }
启动命令:
webpack server
//package.json文件: "scripts": { "dev": "webpack server", "build": "webpack" }, //开发阶段 npm run dev 不会打包到磁盘 //生产阶段 npm run build 打包生成到磁盘
引入网络请求工具
下载 npm i axios --save
然后再main.js中引入:
import axios from "axios"
webpack的cli配置中有--watch的观察模式 为什么还要配置服务?或者说devServer的优势是什么?
答:
devServer的功能是:当文件发生修改,通知各个模块进行更新加载,加载到计算机内存,刷新浏览器
1.项目中加载的东西很多.内存刷新 比磁盘刷新反应快
2.热更新使得开发调试效率更高
3.自动配置代理 比手动设计代理服务器更方便
webpack 的构建流程是什么?从读取配置到输出文件这个过程
答:
webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
1、初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数
2、开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译
3、确定入口:根据配置中的 entry 找出所有的入口文件
4、编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
5、完成模块编译:在经过第 4 步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
6、输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk, 再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
7、输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统,在以上过程中,webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用webpack 提供的API改变 webpack 的运行结果
如何利用 webpack 来优化前端性能
答:1、压缩代码。uglifyJsPlugin 压缩 js 代码, mini-css-extract-plugin 压缩css代码
2、利用 CDN 加速,将引用的静态资源修改为 CDN 上对应的路径,可以利用webpack对于 output 参数和 loader 的 publicpath 参数来修改资源路径
3、删除死代码(tree shaking),css 需要使用 Purify-CSS
4、 提取 公共 代码集成为模块 。