webpack+vite前端构建工具 - 1为什么要构建工具 2webpack基础配置
1 为什么要构建工具
1.1 为什么要构建
为什么需要webpack、vite构建工具对项目进行处理呢?
1.2 开发和生产的矛盾
1.1.1 矛盾1——浏览器不能识别模块化——核心矛盾
打包:将不同的模块文件打包成一个文件。
开发需要模块化,将不同的功能文件拆分成一个个js文件,需要的时候import模块,比如发请求import axios等。没有模块化所有的文件写到一个文件里——麻烦。
问题来了——浏览器无法解析import(引用b.js的a.js,直接在浏览器运行,会报错),只能执行一个个文件。开发必须模块化,浏览器不能识别模块化。
解决——构建工具webpack等解决——即webpack诞生的根本意义。
开发时模块化,开发完成后打包,将模块化的文件通过构建工具打包成一个文件,浏览器可执行这个文件——既模块化,还可在浏览器执行。
1.1.2 矛盾2——浏览器不能解析特殊写法
特殊语法,例如ts,es6新特性,vue项目(.vue文件),浏览器不能解析。浏览器只能执行js文件,例如ts, vue,es6(老的浏览器可能不支持,出于兼容性考虑,需要编译为es5)等编译为浏览器可以解析的代码。
解决——构建工具——将方便开发但不能由浏览器解析的代码编译为浏览器可解析的js
1.1.3 总结
- 开发
- 需要模块化,帮助更好开发
- 会用一些新语法和框架特殊写法(ts, es6,vue)
- 生产
- 浏览器自身无法解析模块化
- 浏览器只能解析js,有的老浏览器对es6支持不全
1.3 构建工具帮助我们做了什么
- 编译浏览器无法理解的东西
- es6
- ts
- .vue
- 代替一些人工操作
- 文件合并和拆分
- 图片压缩
- 资源处理
- 帮助开发
- 开发模式
webpack自身只做了打包工作(将引入的模块打包成一个文件),编译工作(ts, es6还有.vue的编译)需要额外的插件如loader完成。
2 webpack基础配置
2.1 webpack到底做了什么
2.2 webpack配置项简介
- 配置项
- entry:必填项,以哪个文件开始,分析引用关系
- output:必填项,最终产出js配置
- mode:webpack4以后必填
- devServer:非必填,开发模式配置
- module:非必填,loader编写的地方
- plugins:非必填,插件
- optimization:非必填,优化相关
- resolve:非必填,提供一些简化功能
2.2.1 mode
模式名称 | 配置中使用的模式名字 | 特点 | 使用场景 |
---|---|---|---|
开发模式 | development | 特点是快:快速调试代码,实时加载,模块热替换等,可以更快速地开发项目 | 本地开发 |
生产模式 | production | 特点是代码体积小:尽可能地压缩代码、资源优化、使项目体积更轻量等 | 打包上线 |
无模式 | none | 无优化:不会启用任何代码优化功能。灵活性极高:开发者需要自己手动配置所有的优化选项。 | 适合高度定制的场景,例如在一些性能测试或特殊的开发流程中 |
2.3 安装webpack
注意
之前使用到的打包:npm run dev,即使用项目中的webpack打包
webpack安装:全局webpack,项目本地webpack
版本 | 命令 | 备注 |
---|---|---|
<=3 | npm install webpack@3.023 | 需指定版本 |
5 | npm install webpack | 直接安装webpack则版本为5 |
>=4 | npm install webpack webpack-cli -g | 4以后的版本,除了webpack本身,还需要安装webpack-cli |
2.3.1 全局安装
命令:npm install webpack webpack-cli -g
-g全局安装
安装成功
查询版本,命令webpack -v
2.3.2 项目中指定版本
- 项目里初始一个package.json文件:
npm init -y
- 指定安装webpack4.21版本:
npm install webpack@4.21
安装成功后,项目的package.json的dependencies字段会多一个webpack属性.
此时,在scripts里写一个dev属性,值为webpack。此时执行webpack命令,则会用本地的版本,例如本项目的webpack版本是4
{"name": "webpackDemo","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev": "webpack"},"keywords": [],"author": "","license": "ISC","dependencies": {"webpack": "^4.21.0"}
}
2.4 webpack打包案例
要对app.js和a.js进行打包。
// app.js
import b from './a.js'(() => {let a = 23;console.log(b);console.log(a);
})()
// a.js
let b = 3;
console.log(b);
export default b + 1;
2.4.1 创建打包配置文件webpack.config.js
开始打包
step1 编辑打包配置,新建webpack.config.js文件,在项目根目录下
文件名可自定义命名,默认为webpack.config.js
打包命令webpack
默认会查找项目根目录下的webpack.config.js文件
如果是其他名称,则打包命令为webpack --config webpack.config1.js
2.4.2 配置打包配置项
step2 配置打包配置项
// 1 打包配置编写在一个对象中
// 2 export对象
// 3 编写配置使用commonjs规范(node环境的模块化规范)
// 4 import export暴露模块是es6的module写法,不可在webpack的配置文件里使用
// 因为webpack本身使用node编写,在node环境运行。node使用commonjs规范,因此import写法是node不允许的
// 5 webpack配置需要用node编写
// 6 业务代码里可以用require, commonjs,因为业务代码最终是要编译的,而配置文件是不编译的,直接在node环境运行
// 7 entry推荐写为对象,一个入口对应一个打包文件
// 8 output,打包的目标目录,出口路径必须是绝对路径
// 9 mode: (1)production生产模式,压缩代码、简化代码(webpack3及之前都是需要手动实现的功能,webpack及之后,原则开发少写配置,只需要修改mode)(2)development开发模式,不需要压缩或简化代码;(3)none: 什么都不做module.exports = {// entry: "./app.js",//单入口写法,入口指定为app.jsentry: { // 多入口写法:入口名称+入口文件app1: ["./app.js"],// app2: './app2.js'},// entry: ["./app.js", './app2.js'] // 两个文件同时作为一个入口output: {path: __dirname + '/dist', // 绝对路径,__dirname是node的全局变量,表示当前目录的绝对路径filename: "[name].[hash:4].bundle.js", //将name加到filename里,打包结果文件是app.bundle.js和app2.bundle.js,hash是对文件是否有改变的标志,:4表示截取前4位},mode: "production" //webpack4以后要指定mode
}
2.4.3 执行打包命令
step3 执行打包命令
webpack
打包成功,在dist文件夹下有一个app1.332d.bundle.js
// app1.332d.bundle.js
(()=>{"use strict";console.log(3),console.log(4),console.log(23)})();
2.4.4 打包文件介绍
生产模式production
step4 打包文件介绍
// a.js
let b = 3;
console.log(b);
export default b + 1;
line3,console.log(3)
line4, export b+1
// app.js
import b from './a.js'(() => {let a = 23;console.log(b);console.log(a);
})()
line6, b是a.js暴露出来的,是3+1,即4,console.log(4)
line7,console.log(23)
webpack将app.js和a.js打包成一个文件,并简化代码——生产模式下的功能
生产模式打包文件
// app1.332d.bundle.js
(()=>{"use strict";console.log(3),console.log(4),console.log(23)})();
开发模式development
开发模式打包文件(不会压缩和简化代码)
/** ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").* This devtool is neither made for production nor for readable output files.* It uses "eval()" calls to create a separate source file in the browser devtools.* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)* or disable the default devtool with "devtool: false".* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).*/
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({/***/ "./a.js":
/*!**************!*\!*** ./a.js ***!\**************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nlet b = 3;\r\nconsole.log(b);\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (b + 1);\n\n//# sourceURL=webpack://webpackDemo/./a.js?");/***/ }),/***/ "./app.js":
/*!****************!*\!*** ./app.js ***!\****************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _a_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./a.js */ \"./a.js\");\n\r\n\r\n(() => {\r\n let a = 23;\r\n console.log(_a_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\r\n console.log(a);\r\n})()\n\n//# sourceURL=webpack://webpackDemo/./app.js?");/***/ })/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module can't be inlined because the eval devtool is used.
/******/ var __webpack_exports__ = __webpack_require__("./app.js");
/******/
/******/ })()
;
无模式none
none无模式
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ([
/* 0 */,
/* 1 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
let b = 3;
console.log(b);
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (b + 1);/***/ })
/******/ ]);
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
(() => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _a_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);(() => {let a = 23;console.log(_a_js__WEBPACK_IMPORTED_MODULE_0__["default"]);console.log(a);
})()
})();/******/ })()
;
补充:webpack安装失败
报错:Error: Cannot find module ‘node:events’
参考https://blog.csdn.net/qq_42996171/article/details/128831372
更新node版本
2.5 webpack其他配置项
2.5.1 loader
写法格式
module.exports = {// loadermodule: {rules: [{// 每个对象是一个loader},{} ]}
}
示例
module.exports = {// loadermodule: {rules: [{// 每个对象是一个loadertest: /\.js/,loader: "babel-loader"}]}
}
2.5.2 插件plugins
写法
// 引入插件
const plugins = require('plugins')
module.exports = {plugins: [new plugins({// 插件配置})]
}
2.5.3 devServer
写法格式
module.exports = {devServer: {}
}
2.5.4 resolve
写法格式
module.exports = {resolve: {}
}
2.5.5 optimization
写法格式
module.exports = {optimization: {}
}
2.5.6 总结
webpack配置8项