前端知识点——手写简单Webpack

写在前面

笔记内容大多出自于拉勾教育大前端高薪训练营的教程,因此也许会和其他文章雷同较多,请担待。

webpack

  • 打包后的文件就是一个自调用函数,当前函数调用时传入一个对象
  • 这个对象我们为了方便将之称为是模块定义,他就是一个键值对
  • 这个键名就是当前被加载模块的文件名和某个目录的拼接
  • 这个键值就是一个函数,和node.js里的模块加载有一些类似,会将被加载模块中的内容包裹于一个函数中
  • 这个函数在将来某个时间点上会被调用,同时接收一定的参数,利用这些参数就可以实现模块的加载操作
  • 默认commonJS规范
  • 两个模块的规范可以不同,但一个模块内只能用一种规范,否则会报错 -> Uncaught TypeError: Cannot assign to read only property ‘exports’ of object ‘#’
$ npm i webapck webpack-cli --dev
$ md webpack.config.js
// webpack.config.js
const path = require('path')
module.exports = {
   
  mode: 'development', // 打包模式 development / production
  entry: './src/index.js', // 打包入口文件
  output: {
   
    filename: 'bundle.js', // 输出文件名
    path: path.join(__dirname, 'dist'), // 输出路径,因为必须绝对路径,所以使用path来生成绝对路径
    publicPath: 'dist/' // 网站的根目录,因为在未打包index.html时已完成打包的资源文件会进入dist,但对于没有打包的index.html来说并不会改变引用路径,所以需要重新指定资源文件的路径,从dist下面寻找
  },
  module: {
   
    rules: [
      {
   
        test: /.css$/,
        loader: [
          'style-loader', // 将css文件打包成的js文件进行引用
          'css-loader' // 将css文件打包成js文件
        ]
      },
      /* ---------------- start ---------------- */
      // 将小文件交给url-loader去转换为Base64,优化加载速率
      // 将大文件交给file-loader去生成新资源并修改路径,因为大文件转换为Base64之后也许会更大
      {
   
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: 'file-loader' // 该loader可以处理图片、音视频、字体的路径
      },
      {
   
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: {
   
          loader: 'url-loader', // 该loader可以处理图片、音视频、字体的本体,将其转换为Base64
          options: {
   
            limit: 10 * 1024 // 10kb
          }
        }
      }
      /* ---------------- end ---------------- */
    ]
  }
}

简单打包两个文件,其中index.js引用了header.js

webpack 原理

// dist/main.js
(function (modules) {
   
  // 当模块已被加载则会放入缓存
	var installedModules = {
   };
  // 核心作用是返回模块的exports
	function __webpack_require__(moduleId) {
   
    // 判断该模块是否已加载过
		if (installedModules[moduleId]) {
   
			return installedModules[moduleId].exports;
		}
    // 为加载模块初始化
		var module = installedModules[moduleId] = {
   
			i: moduleId,
			l: false,
			exports: {
   }
		}
    // 执行模块内方法
		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)
    // 模块已加载
		module.l = true
    // 返回模块返回的信息
		return module.exports
	}
  // 将传入的模块缓存到属性 m 上 - modules
	__webpack_require__.m = modules
  // 将已加载模块缓存到属性 c 上 - cache
	__webpack_require__.c = installedModules
  // 判断对象身上是否有某属性 - hasOwnProperty
	__webpack_require__.o = function (object, property) {
   
    return Object.prototype.hasOwnProperty.call(object, property)
  }
  // 为exports定义属性 - defineProperty
	__webpack_require__.d = function (exports, name, getter) {
   
		if (!__webpack_require__.o(exports, name)) {
   
			Object.defineProperty(exports, name, {
   
        enumerable: true,
        get: getter
      })
		}
	}
  // 为exports挂载__esModule: true属性 - redefine
	__webpack_require__.r = function (exports) {
   
    // 判断是否是es6,简而言之就是为了判断是否是ES Module
    // Object.property.toString.call(exports) -> Module
		if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
   
			Object.defineProperty(exports, Symbol.toStringTag, {
   
        value: 'Module'
      })
		}
		Object.defineProperty(exports, '__esModule', {
   
      value: true
    })
	}
	__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
	}
	__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
	}
  // path
	__webpack_require__.p = ""
	return __webpack_require__(__webpack_require__.s = "./src/index.js")
})

index.js使用require导入模块/module.exports导出模块(CommonJS) <------> header.js使用module.export导出模块(CommonJS)

// index.js
const header = require('./header')
console.log('index 内容 -> next:', header)
module.exports = 'here entry'
// header.js
console.log('header 内容')
module.exports = 'here header'
// dist/main.js
({
   
  "./src/header.js":
    (function (module, exports) {
   
      console.log('header 内容')
      module.exports = 'here header'
    }),
  "./src/index.js":
    (function (module, exports, __webpack_require__) {
   
      const header = __webpack_require__("./src/header.js")
      console.log('index 内容 -> next:', header)
      module.exports = 'here entry'
    })
})

index.js使用require导入模块/module.exports导出模块(CommonJS) <------> header.js使用export default导出模块(ES Module)

// index.js
const header = require('./header')
console.log('index 内容 -> next:', header)
module.exports = 'here entry'
// header.js
console.log('header 内容')
export default 'here header'
// dist/main.js
({
   
  "./src/header.js":
    (function (module, __webpack_exports__, __webpack_require__) {
   
      "use strict"
      __webpack_require__.r(__webpack_exports__)
      console.log('header 内容')
      __webpack_exports__["default"] = ('here header')
    }),
  "./src/index.js":
    (function (module, exports, __webpack_require__) {
   
      const header = __webpack_require__("./src/header.js")
      console.log('index 内容 -> next:', header)
      module.exports = 'here entry'
    })
})

index.js使用import导入模块/export default导出模块(ES Module) <-----> header.js使用module.export导出模块(CommonJS)

// index.js
import header from './header'
console.log('index 内容 -> next:', header)
export default 'here entry'
// header.js
console.log('header 内容')
module.exports = 'here header'
// dist/main.js
({
   
  "./src/header.js":
    (function (module, __webpack_exports__, __webpack_require__) {
   
      "use strict"
      __webpack_require__.r(__webpack_exports__)
      console.log('header 内容')
      __webpack_exports__["default"] = ('here header')
    }),
  "./src/index.js":
    (function (module, __webpack_exports__, __webpack_require__) {
   
      "use strict"
      __webpack_require__.r(__webpack_exports__)
      var _header__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/header.js")
      console.log('index 内容 -> next:', _header__WEBPACK_IMPORTED_MODULE_0__["default"])
      __webpack_exports__["default"] = ('here entry')
    })
})

index.js使用import导入模块/export const导出模块(ES Module) <-------> header.js使用export default导出模块(ES Module)

// index.js
import header from './header'
console.log('index 内容 -> next:', header)
export const message = 'here entry'
// header.js
console.log('header 内容')
export default 'here header'
// dist/main.js
({
   
  "./src/header.js":
    (function (module, __webpack_exports__, __webpack_require__) {
   
      "use strict"
      __webpack_require__.r(__webpack_exports__)
      console.log('header 内容')
      __webpack_exports__["default"] = ('here header')
    }),
  "./src/index.js":
    (function (module, __webpack_exports__, __webpack_require__) {
   
      "use strict"
      __webpack_require__.r(__webpack_exports__)
      __webpack_require__.d(__webpack_exports__, "message", function () {
   
        return message
      })
      var _header__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/header.js")
      console.log('index 内容 -> next:', _header__WEBPACK_IMPORTED_MODULE_0__["default"])
      const message = 'here entry'
    })
})
  • import()可以实现模块的懒加载
  • 懒加载的核心原理就是jsonp
  • webpack_require.t方法可以针对内容进行不同的处理(取决于二进制位运算符的布尔值)

懒加载

webpack 原理

(function (modules) {
   
	function webpackJsonpCallback(data) {
   
		var chunkIds = data[0]
		var moreModules = data[1]
		var moduleId, chunkId, i = 0, resolves = [];
		for (; i < chunkIds.length; i++) {
   
			chunkId = chunkIds[i]
			if (Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
   
				resolves.push(installedChunks[chunkId][0])
			}
			installedChunks[chunkId] = 0
		}
		for (moduleId in moreModules) {
   
			if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
   
				modules
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值