前言
作为前端开发者,置信大家或多或少都接触过webpack
,现如今webpack
曾经浸透在了前端的各个方面,所以咱们有必要来理解并学习webpack
,webpack
是一种用于构建 JavaScript 应用程序的动态模块打包器,它可能以一种绝对统一且凋谢的解决形式,加载利用中的所有资源文件(图片、CSS、视频、字体文件等),并将其合并打包成浏览器兼容的 Web 资源文件。webpack
相比其它构建工具性能更加弱小,可扩展性也更强,它可能交融多种工程化工具,将开发阶段的利用代码编译、打包成适宜网络散发、客户端运行的利用产物。
外围概念
输入输出
entry
webpack的构建入口,入口终点(entry point) 批示 webpack 应该应用哪个模块,来作为构建其外部 依赖图(dependency graph) 的开始。进入入口终点后,webpack 会找出有哪些模块和库是入口终点(间接和间接)依赖的。
// 单入口module.exports = { entry: './src/main.js'}// 多入口module.exports = { entry: { a: './src/a.js', b: './src/b.js' }}
output
output 属性通知 webpack 在哪里输入它所创立的 bundle,以及如何命名这些文件。次要输入文件的默认值是./dist/main.js
,其余生成文件默认搁置在./dist
文件夹中。
// 单入口module.exports = { entry: './src/main.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }}// 多入口module.exports = { entry: { a: './src/a.js', b: './src/b.js' }, output: { filename: '[name].[hash:6].js', // 通过占位符确保文件名惟一,思考缓存问题,还能够为文件名加上hash path: __dirname + '/dist', publicPath: '/', // 生产环境个别是CDN地址,开发环境配置为/或不配置 }}
模块解决
loader
webpack 只能了解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 可能去解决其余类型的文件,并将它们转换为无效 模块,以供应用程序应用,以及被增加到依赖图中。
比方:配置webpack为css文件利用css-loader
module.exports = { module: { rules: [ {test: /.css$/, use: 'css-loader'} ] }}
module.rules
容许你在 webpack 配置中指定多个 loader。 这种形式是展现 loader 的一种扼要形式,并且有助于使代码变得简洁和易于保护。
plugin
插件 是 webpack 的 支柱 性能。Webpack 本身也是构建于你在 webpack 配置中用到的 雷同的插件零碎 之上!
插件目标在于解决 loader 无奈实现的其余事。Webpack 提供很多开箱即用的 插件。
比方:为编译过程增加进度报告插件
const Webpack = require('webpack')module.exports = { plugins: [new Webpack.ProgressPlugin()]}
resolve
用于配置模块门路解析规定,可用于帮忙 Webpack 更准确、高效地找到指定模块
比方配置别名:
创立 import
或 require
的别名,来确保模块引入变得更简略。例如,一些位于 src/
文件夹下的罕用模块:
module.exports = { resolve: { alias: { node_modules: path.resolve(__dirname, './node_modules'), '@': path.resolve(__dirname, './src'), api: path.resolve(__dirname, './src/api'), components: path.join(__dirname, './src/components'), } }}
module
这些选项决定了如何解决我的项目中的不同类型的模块。
比方咱们常见的loader就是在module.rules
内配置的。
module.exports = { module: { rules: [ {test: /.css$/, use: 'css-loader'} ] }}
externals
用于申明内部资源,Webpack 会间接疏忽这部分资源,跳过这些资源的解析、打包操作
比方避免将某些 import
的包(package)打包到 bundle 中,而是在运行时(runtime)再去从内部获取这些扩大依赖(external dependencies) 。
比方:从CDN引入Vue
<!-- index.html --><script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.3/vue.min.js"></script>
// webpack.config.jsmodule.exports = { externals: { vue: 'vue' }}
后处理
optimization
用于管制如何优化产物包体积,内置 Dead Code Elimination、Scope Hoisting、代码混同、代码压缩等性能
从 webpack 4 开始,会依据你抉择的
mode
来执行不同的优化, 不过所有的优化还是能够手动配置和重写。
module.exports = { //... optimization: { chunkIds: 'named', },};
target
用于配置编译产物的指标运行环境,反对 web、node、electron 等值,不同值最终产物会有所差别
比方:target设置为node,webpack将在node环境下进行编译
module.exports = { target: 'node'}
mode
提供 mode
配置选项,告知 webpack 应用相应模式的内置优化。
string = 'production': 'none' | 'development' | 'production'
module.exports = { mode: 'development',};
或者从cli--mode
参数进行传递
webpack --mode development
开发效率
watch
启用 Watch 模式。这意味着在初始构建之后,webpack 将持续监听任何已解析文件的更改。
module.exports = { watch: true}
⚠️留神:webpack-dev-server
和webpack-dev-middleware
默认是开启watch模式的
devtool
此选项管制是否生成,以及如何生成 source map。
string = 'eval' | false
抉择一种 source map 格调来加强调试过程。不同的值会显著影响到构建(build)和从新构建(rebuild)的速度。
devServer
用于配置与 HMR 强相干的开发服务器性能
通过 webpack-dev-server 的这些配置,可能以多种形式扭转其行为,这里比拟常见的配置有:port
、host
、proxy
等
module.exports = { devServer: { static: { directory: path.join(__dirname, 'public'), }, compress: true, port: 9000, }}
cache
Webpack 5 之后,该项用于管制如何缓存编译过程信息与编译后果
缓存生成的 webpack 模块和 chunk,来改善构建速度。cache
会在开发
模式被设置成 type: 'memory'
而且在 生产
模式 中被禁用。 cache: true
与 cache: { type: 'memory' }
配置作用统一。 传入 false
会禁用缓存:
module.exports = { cache: false}
上手配置
理解完下面这些webpack外围概念,咱们能够尝试来手动配置好一个Vue开发环境
初始化我的项目
首先npm init -y
初始化package.json
文件
接着装置好咱们的webpack
、webpack-cli
npm i webpack webpack-cli -D
⚠️留神: 我这里的webpack是5版本的
"webpack": "^5.85.1","webpack-cli": "^4.7.2",
解决Vue代码
原生 Webpack 并不能解决这种内容格局的文件,为此咱们须要引入专用于 Vue SFC 的加载器:vue-loader
npm i vue-loader
// webpack.config.jsconst Webpack = require('webpack')const {VueLoaderPlugin} = require('vue-loader')module.exports = { entry: './src/main.js', output: { filename: 'bundle.[hash:6].js', path: __dirname + '/dist', }, module: { rules:[ {test: /.vue$/, use: 'vue-loader'}, ] }, plugins:[ new Webpack.ProgressPlugin(), new VueLoaderPlugin(), ],}
提醒:vue-loader
库同时提供用于解决 SFC 代码转译的 Loader 组件,与用于解决上下文兼容性的 Plugin 组件,两者须要同时配置能力失常运行。
此时咱们的文件构造是这样的,大抵与Vue我的项目构造统一
尝试启动看一下:
// package.json"dev": "webpack --mode development",
npm run dev
因为咱们的vue文件中有css内容,而webpack默认是不了解css内容的,所以导致报错了
解决CSS内容
这里须要装置style-loader
、css-loader
来进行解决。
批改webpack配置
// webpack.config.jsconst Webpack = require('webpack')const {VueLoaderPlugin} = require('vue-loader')module.exports = { entry: './src/main.js', output: { filename: 'bundle.[hash:6].js', path: __dirname + '/dist', }, module: { rules:[ {test: /.vue$/, use: 'vue-loader'}, { test: /.css$/, use: ['style-loader', 'css-loader'] } ] }, plugins:[ new Webpack.ProgressPlugin(), new VueLoaderPlugin(), ],}
此时再跑起来,发现没有报错了。
解决JS内容
咱们平时在开发中必定会用到ES6
语法,这里咱们也须要配置对应的loader
来进行解决
装置babel-loader
npm i babel-loader @babel/preset-env @babel/core
配置
module.exports = { module: { rules: [ { test: /.js$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } }, exclude: /node_modules/ } ] }}
当然这里的options配置你也能够在.babelrc
或babel.config.js
中独自配置。
解决图片资源
与CSS一样,webpack也是默认不了解图片的,所以这里也须要配置loader进行解决。
webpack4
在webpack4中,咱们罕用的解决图片的loader有:file-loader
、url-loader
file-loader
将文件发送到输入目录
// webpack.config.jsmodule.exports = { // ... module: { rules: [{ test: /.(png|jpg|gif|jpeg)$/, use: ['file-loader'] }], },};
通过 file-loader
解决后,原始图片会被重命名并复制到产物文件夹,同时在代码中插入图片 URL 地址
url-loader
将文件作为 data URI 内联到 bundle 中,它有两种体现,对于小于阈值limit
的图像间接转化为 base64 编码;大于阈值的图像则调用file-loader
进行加载
module.exports = { // ... module: { rules: [{ test: /.(png|jpg|gif|jpeg)$/, use: [{ loader: 'url-loader', options: { limit: 1024 } }] }], },};
通过 url-loader
解决后,小于 limit
参数即 1024B 的图片会被转译为 Base64 编码,对于超过 limit
值的图片则间接调用 file-loader
实现加载。
webpack5
file-loader
、url-loader
并不局限于解决图片,它们还能够被用于加载任意类型的多媒体或文本文件,应用频率极高,简直曾经成为标配组件!所以 Webpack5 间接内置了这些能力,开箱即可应用。
用法上,本来须要装置、导入 Loader,Webpack5 之后只须要通过 module.rules.type
属性指定资源类型即可
比方:
module.exports = { // ... module: { rules: [{ test: /.(png|jpg|gif|jpeg)$/, type: 'asset/resource' }], },};
运行页面
配置了这么多内容,咱们却还不能看到页面的内容,心里必定不乐意,下面这几步操作其实就相当于翻译 Vue SFC 文件的内容,接下来咱们还须要让页面真正运行起来。
粗犷计划
有一种疾速验证咱们的打包配置是否正确:咱们只须要新建一个html文件,将打包产物引入进去,并创立好挂载节点就能够
<!-- public/index.html --><!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head><body> <div id="app"></div> <script src="../dist/bundle.42603d.js"></script></body></html>
咱们再把这个html文件在浏览器关上,就能看到咱们vue我的项目可能失常关上了。
这种计划有一种弊病就是:咱们打包进去的文件个别都会带有hash
,那就须要咱们每次在打包完后去html
文件批改引入的文件,这样是不是有点太吃力了,你们能忍吗?
优雅计划
下面那种计划在日常开发中显然是不能承受的,身为程序员能偷懒的中央必须得偷懒!
咱们能够利用上面两个工具让这个过程变得更加智能化、自动化。
html-webpack-plugin: 主动生成 HTML 页面
HtmlWebpackPlugin
简化了 HTML 文件的创立,以便为你的 webpack 包提供服务。这对于那些文件名中蕴含哈希值,并且哈希值会随着每次编译而扭转的 webpack 包特地有用。
webpack-dev-server :让页面真正运行起来,并具备热更新能力。
webpack-dev-server
次要提供两种性能:
- 联合 Webpack 工作流,提供基于 HTTP(S) 协定的动态资源服务;
- 提供资源热更新能力,在放弃页面状态前提下自动更新页面代码,晋升开发效率。
装置
npm i html-webpack-plugin webpack-dev-server
批改配置
const Webpack = require('webpack')const {VueLoaderPlugin} = require('vue-loader')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { entry: './src/main.js', output: { filename: 'bundle.[hash:6].js', path: __dirname + '/dist', }, module: { rules:[ {test: /.vue$/, use: 'vue-loader'}, { test: /.css$/, use: ['style-loader', 'css-loader'] }, { test: /.js$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } }, exclude: /node_modules/ }, { test: /.(png|jpg|gif|jpeg)$/, type: 'asset/resource', } ] }, plugins:[ new Webpack.ProgressPlugin(), new VueLoaderPlugin(), new HtmlWebpackPlugin({ template: './public/index.html', filename: 'index.html' }) ], devServer: { hot: true, open: true }}
批改启动脚本
"dev": "webpack serve --mode development"
运行
npm run dev
这时webpack就能主动帮咱们关上浏览器运行页面了
vue文件内容如下:
<template> <div class="title">webpack + vue -- {{ name }}</div> <img src="../asset/1.png" class="top_bg" /></template><script setup>import { ref } from 'vue'const name = ref('前端南玖')</script><style>.title { font-size: 16px; font-weight: bold; color: salmon;}.top_bg { width: 100%; height: auto;}</style>
如果这篇文章有帮忙到你,❤️关注+点赞❤️激励一下作者,文章公众号首发,关注 前端南玖
第一工夫获取最新文章~