webpack打包原理入门探究(一)
周五晚上发布了计划,计划一出来,就要坚定执行,不然怎么算得上男人这个称号呢?昨天已经研究了 vue 一些常用的 组件,也已经整理到自己的组件学习库中了,喜欢的伙伴可以点赞,收藏加评论,一...
周五晚上发布了计划,计划一出来,就要坚定执行,不然怎么算得上男人这个称号呢?昨天已经研究了 vue 一些常用的 组件,也已经整理到自己的组件学习库中了,喜欢的伙伴可以点赞,收藏加评论,一起进步吧
最近甚是好奇 vue-cli3 到底是怎么打包压缩分离 html,css,js 的到底哪些所谓的 loader 是起到什么样的作用,嗯,正是这个好奇心,促使我开始研究 webpack
好的,开始进入主题
第一:需要 npm 初始化项目
npm init
{
"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使用命令行工具)
npm install webpack webpack-cli -g
第三:本地也需要安装 webpack,webpack-cli
npm install webpack webpack-cli --save-dev
ok,到此为止,我们把需要的工具依赖已经安装完毕了,我们再来看看 package.json 有何变化,新增了 devDependencies (本地开发依赖),不懂 package.json 配置的,可以看看下面文章
子由风:package.json 配置学习
{
"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
console.log("aaaa")
console.log("bbb")
console.log("ccc")
for(let i=0; i<10; i++) {
console.log(i)
}
我们来打包一下:在 cmd 中进入到 项目目录 webpackdemo
webpack hello.js -o hello.min.js
我们会发现,打包是可以打包成功的,但是有个小小的缺陷,发生了如下警告
我们该如何解决呢?实际上这个警告告诉我们,webpack 在打包的时候,需要指定打包的环境,告诉webpack,当前打包是生产环境(production),还是本地开发环境(development)
webpack --mode development hello.js -o hello.min.js
打包成功,没有任何警告,那么我们来阅读一下这个 hello.min.js
/******/ (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 代码如下
console.log("world")
hello.js 代码如下
require('./word')
console.log("aaaa")
console.log("bbb")
console.log("ccc")
for(let i=0; i<10; i++) {
console.log(i)
}
然后,我们在执行一下打包命令
webpack --mode development hello.js -o hello.min.js
再来看看 hello.js 有什么变化
/******/ (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?");
/***/ })
/******/ });
在上面的基础上增加了以下代码,好像没有什么也
/***/ "./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 文件
html,
body {
box-sizing: border-box;
padding: 10px;
background: brown;
}
引入 hello.js
require('./word')
require('./style.css')
console.log("aaaa")
console.log("bbb")
console.log("ccc")
for(let i=0; i<10; i++) {
console.log(i)
}
然后再执行以下打包命令
webpack --mode development hello.js -o hello.min.js
报错了,说是缺少 什么 loader 去加载这种东西,那实际上我们 webpack 加载样式是需要一个 css-loader 这样的东西来加载 css 的,这样 webpack 才能正确处理 css,首先我们需要安装 css-loader
cnpm install css-loader --save-dev
来看看 package.json 又有何变化,看到下面,很正常,安装的依赖都会加到 devDependencies
{
"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 呢?
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'),然后再来执行一下我们的 打包命令
webpack --mode development hello.js -o hello.min.js
这样就打包成功了
第七:我们将打包之后的 hello.min.js 引入一个 index.html,会发生什么?
有人会说控制台会打印出东西,样式会生效,嗯,这句好话只对了一半,是前一半,后一半就不会生效,不信,我们来看看
<!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
npm install style-loader --save-dev
如何使用呢?跟 css-loader 一样
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!,不得麻烦死了,我这懒人肯定不愿意这么干
其实可以使用命令行工具,一样可以打包成功
webpack --mode development hello.js -o hello.min.js --modules-bind 'css=style-loader!css
第九:webpack 其他命令行工具使用
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-
好了,第一篇就暂时到这里吧,接下来第二篇会深入进入主题的,期待吧
更多推荐
所有评论(0)