前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >webpack打包原理入门探究(一)

webpack打包原理入门探究(一)

作者头像
公众号---人生代码
发布2020-06-02 16:56:26
3890
发布2020-06-02 16:56:26
举报
文章被收录于专栏:人生代码人生代码

周五晚上发布了计划,计划一出来,就要坚定执行,不然怎么算得上男人这个称号呢?昨天已经研究了 vue 一些常用的 组件,也已经整理到自己的组件学习库中了,喜欢的伙伴可以点赞,收藏加评论,一起进步吧

最近甚是好奇 vue-cli3 到底是怎么打包压缩分离 html,css,js 的到底哪些所谓的 loader 是起到什么样的作用,嗯,正是这个好奇心,促使我开始研究 webpack

好的,开始进入主题

第一:需要 npm 初始化项目

代码语言:javascript
复制
npm init
代码语言:javascript
复制
{
  "name": "webpackdemo",  // 项目名
  "version": "1.0.0", // 项目版本号
  "description": "", // 一些描述,关于项目是干什么的
  "main": "index.js", // 项目的入口
  "scripts": { // 配置一些命令行脚本
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "", // 项目的作者
  "license": "ISC", // 版权
}

第二:需要全局安装 webpack,webpack-cli(webpack使用命令行工具)

代码语言:javascript
复制
npm install webpack webpack-cli -g

第三:本地也需要安装 webpack,webpack-cli

代码语言:javascript
复制
npm install webpack webpack-cli --save-dev

ok,到此为止,我们把需要的工具依赖已经安装完毕了,我们再来看看 package.json 有何变化,新增了 devDependencies (本地开发依赖),不懂 package.json 配置的,可以看看下面文章

子由风:package.json 配置学习

代码语言:javascript
复制
{
  "name": "webpackdemo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.10"
  }
}

我们来瞄一下 demo 的目录吧

第四:我们来创建一个 hello.js

代码语言:javascript
复制
console.log("aaaa")
console.log("bbb")
console.log("ccc")
for(let i=0; i<10; i++) {
    console.log(i)
}

我们来打包一下:在 cmd 中进入到 项目目录 webpackdemo

代码语言:javascript
复制
webpack hello.js -o hello.min.js

我们会发现,打包是可以打包成功的,但是有个小小的缺陷,发生了如下警告

我们该如何解决呢?实际上这个警告告诉我们,webpack 在打包的时候,需要指定打包的环境,告诉webpack,当前打包是生产环境(production),还是本地开发环境(development)

代码语言:javascript
复制
webpack --mode development hello.js -o hello.min.js

打包成功,没有任何警告,那么我们来阅读一下这个 hello.min.js

代码语言:javascript
复制
/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = "./hello.js");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./hello.js":
/*!******************!*\
  !*** ./hello.js ***!
  \******************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

eval("__webpack_require__(/*! ./word */ \"./word.js\")\r\n__webpack_require__(/*! style-loader!css-loader!./style.css */ \"./node_modules/_style-loader@1.0.0@style-loader/dist/index.js!./node_modules/_css-loader@3.2.0@css-loader/dist/cjs.js!./style.css\")\r\nconsole.log(\"aaaa\")\r\nconsole.log(\"bbb\")\r\nconsole.log(\"ccc\")\r\nfor(let i=0; i<10; i++) {\r\n    console.log(i)\r\n}\n\n//# sourceURL=webpack:///./hello.js?");

/***/ })

});

首先是 (function(module){}),传入了一个模块

定义了一个用于缓存的模块的变量 installedModules

内部定了一个 加载函数 __webpack_require__,传入了模块的ID moduleId

也就是说 webpack ,给每个模块都指定了一个 标志 moduleId,通过这个 id,首先去查找缓存模块变量是否缓存当前传递进来的 id 的模块

如果没有缓存当前这个模块,就创建缓存

执行加载进来的 模块

给定标志表示加载完毕 module.l = true

然后将当前模块,缓存模块暴露出去 __webpack_require__.m = modules;

定义了 es6 module 函数 __webpack_require__.r

定义了 getter 函数 __webpack_require__.d

定义了 mode 模式设置 函数 __webpack_require__.t

定义对象判断函数 __webpack_require__.o

定义了 public_path 共享目录变量 __webpack_require__.p

最后是压缩了的代码 eval 执行

第五:我们在 hello.js 加载第二个 world.js

world.js 代码如下

代码语言:javascript
复制
console.log("world")

hello.js 代码如下

代码语言:javascript
复制
require('./word')
console.log("aaaa")
console.log("bbb")
console.log("ccc")
for(let i=0; i<10; i++) {
    console.log(i)
}

然后,我们在执行一下打包命令

代码语言:javascript
复制
webpack --mode development hello.js -o hello.min.js

再来看看 hello.js 有什么变化

代码语言:javascript
复制
/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = "./hello.js");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./hello.js":
/*!******************!*\
  !*** ./hello.js ***!
  \******************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

eval("__webpack_require__(/*! ./word */ \"./word.js\")\r\n__webpack_require__(/*! style-loader!css-loader!./style.css */ \"./node_modules/_style-loader@1.0.0@style-loader/dist/index.js!./node_modules/_css-loader@3.2.0@css-loader/dist/cjs.js!./style.css\")\r\nconsole.log(\"aaaa\")\r\nconsole.log(\"bbb\")\r\nconsole.log(\"ccc\")\r\nfor(let i=0; i<10; i++) {\r\n    console.log(i)\r\n}\n\n//# sourceURL=webpack:///./hello.js?");

/***/ }),

/***/ "./word.js":
/*!*****************!*\
  !*** ./word.js ***!
  \*****************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("console.log(\"word\")\n\n//# sourceURL=webpack:///./word.js?");

/***/ })

/******/ });

在上面的基础上增加了以下代码,好像没有什么也

代码语言:javascript
复制
/***/ "./word.js":
/*!*****************!*\
  !*** ./word.js ***!
  \*****************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("console.log(\"word\")\n\n//# sourceURL=webpack:///./word.js?");

/***/ })

第六:那其实我想看看如果在 hello.js 直接引入 style.css 会发生什么?

我们随便创建一个 style.css 文件

代码语言:javascript
复制
html,
body {
    box-sizing: border-box;
    padding: 10px;
    background: brown;
}

引入 hello.js

代码语言:javascript
复制
require('./word')
require('./style.css')
console.log("aaaa")
console.log("bbb")
console.log("ccc")
for(let i=0; i<10; i++) {
    console.log(i)
}

然后再执行以下打包命令

代码语言:javascript
复制
webpack --mode development hello.js -o hello.min.js

报错了,说是缺少 什么 loader 去加载这种东西,那实际上我们 webpack 加载样式是需要一个 css-loader 这样的东西来加载 css 的,这样 webpack 才能正确处理 css,首先我们需要安装 css-loader

代码语言:javascript
复制
cnpm install css-loader --save-dev

来看看 package.json 又有何变化,看到下面,很正常,安装的依赖都会加到 devDependencies

代码语言:javascript
复制
{
  "name": "webpackdemo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^3.2.0",
    "style-loader": "^1.0.0",
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.10"
  }
}

那么,我们该如何使用 css-loader 呢?

代码语言:javascript
复制
require('./word')
require('css-loader!./style.css')
console.log("aaaa")
console.log("bbb")
console.log("ccc")
for(let i=0; i<10; i++) {
    console.log(i)
}

看到没有,在require('./style.css'),之前我们需要先使用 css-loader 处理一下,所以就变成了 require('css-loader!./style.css'),然后再来执行一下我们的 打包命令

代码语言:javascript
复制
webpack --mode development hello.js -o hello.min.js

这样就打包成功了

第七:我们将打包之后的 hello.min.js 引入一个 index.html,会发生什么?

有人会说控制台会打印出东西,样式会生效,嗯,这句好话只对了一半,是前一半,后一半就不会生效,不信,我们来看看

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script src="./hello.min.js"></script>
</body>
</html>

我们来浏览器跑一下,便知道什么情况了,打印是打印出来了,但是背景颜色没有生效

什么情况,不是有 css-loader 了?实际上 css-loader 不能使得样式在 浏览器生效,还得借助一个 loader,此loader 叫做 style-loader

代码语言:javascript
复制
npm install style-loader --save-dev

如何使用呢?跟 css-loader 一样

代码语言:javascript
复制
require('./word')
require('style-loader!css-loader!./style.css')
console.log("aaaa")
console.log("bbb")
console.log("ccc")
for(let i=0; i<10; i++) {
    console.log(i)
}

我们现在再来看看浏览器,有何变化,变红了

第八:那我就想如果我每次引入的不同样式都要加个 loader!,不得麻烦死了,我这懒人肯定不愿意这么干

其实可以使用命令行工具,一样可以打包成功

代码语言:javascript
复制
webpack --mode development hello.js -o hello.min.js --modules-bind 'css=style-loader!css

第九:webpack 其他命令行工具使用

代码语言:javascript
复制
webpack --mode development hello.js -o hello.min.js --modules-bind 'css=style-loader!css-loader'
/// 加上进度 --progress
webpack --mode development hello.js -o hello.min.js --modules-bind 'css=style-loader!css-loader' --progress
/// 在上面基础上加上 --watch
webpack --mode development hello.js -o hello.min.js --modules-bind 'css=style-loader!css-loader' --progress --watch
/// 再加上 --display-modules
webpack --mode development hello.js -o hello.min.js --modules-bind 'css=style-loader!css-loader' --progress --watch  --display-modules
/// 再加上 --display-reasons
webpack --mode development hello.js -o hello.min.js --modules-bind 'css=style-loader!css-

好了,第一篇就暂时到这里吧,接下来第二篇会深入进入主题的,期待吧

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CryptoCode 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一:需要 npm 初始化项目
  • 第二:需要全局安装 webpack,webpack-cli(webpack使用命令行工具)
  • 第三:本地也需要安装 webpack,webpack-cli
  • 第四:我们来创建一个 hello.js
  • 第五:我们在 hello.js 加载第二个 world.js
  • 第六:那其实我想看看如果在 hello.js 直接引入 style.css 会发生什么?
  • 第七:我们将打包之后的 hello.min.js 引入一个 index.html,会发生什么?
  • 第八:那我就想如果我每次引入的不同样式都要加个 loader!,不得麻烦死了,我这懒人肯定不愿意这么干
  • 第九:webpack 其他命令行工具使用
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档