周五晚上发布了计划,计划一出来,就要坚定执行,不然怎么算得上男人这个称号呢?昨天已经研究了 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-

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

Logo

前往低代码交流专区

更多推荐