We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
打包 src 下的 index.js index.css 到 dist/bundle.js
css 并不能被 webpack 识别,但是可以通过 loader 来将 css 转换成 js
可以分为以下几步实现
package.json
{ "scripts": { "dev": "cross-env NODE_ENV=development webpack", // 开发环境 "build": "cross-env NODE_ENV=production webpack" // 生产环境 }, "dependencies": { "cross-env": "^6.0.3", // 兼容各种环境 "css-loader": "^3.2.0", "rimraf": "^3.0.0", // 删除文件 "webpack": "^4.41.2" }, "devDependencies": { "webpack-cli": "^3.3.10" } }
webpack.config.js
const path = require('path'); const rimraf = require('rimraf'); // 删除 dist 目录 rimraf.sync('dist'); // webpack 配置 module.exports = { entry: './src/index', mode: process.env.NODE_ENV, output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } };
src/index.js
const css = require('css-loader!./index.css'); const a = 100; console.log(a, css);
src/index.css
body { width: 100%; height: 100vh; background-color: orange; }
我删掉了一些注释跟一些干扰内容,这样看起来会更清晰一点
bundle
webpack
0 模块
__webpack_require__
require
dist/bundle.js
(function(modules) { 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; } return __webpack_require__((__webpack_require__.s = 0)); })({ './src/index.js': function(module, exports, __webpack_require__) { eval(` const css = __webpack_require__("./src/style/index.css") const a = 100; console.log(a, css) `); }, './src/style/index.css': function(module, exports, __webpack_require__) { eval(` exports = module.exports = __webpack_require__("./node_modules/css-loader/dist/runtime/api.js")(false); exports.push([module.i, "body { width: 100%; height: 100vh; background-color: orange; }", ""]); `); }, 0: function(module, exports, __webpack_require__) { module.exports = __webpack_require__('./src/index.js'); } });
如果我们把 index.js 的 require 改成 import 会发生什么?
我们知道 import 跟 require 的区别是,import 是动态加载只有在用到的时候才会去加载,而 require 只要声明了就会加载,webpack 遇到了 require 就会把它当成一个模块加载到 bundle 的依赖里
import
那么问题来了,如果我们使用了 import 去引用一个模块,它是如何加载的呢?
// const css = require('css-loader!./index.css'); const css = import('css-loader!./index.css'); const a = 100; console.log(a, css);
除了正常的 bundle 之外,我们还可以看见一个 0.boundle.js
0.boundle.js
0.boundle.js 就是我们的动态加载的 index.css 模块
index.css
|-- bundle.js |-- 0.boundle.js
这个文件就是把我们 import 的模块放进了一个单独的 js 文件中
js
(window['webpackJsonp'] = window['webpackJsonp'] || []).push([ [0], { './node_modules/css-loader/dist/runtime/api.js': function( module, exports, __webpack_require__ ) { 'use strict'; eval(` ... `); }, './src/style/index.css': function(module, exports, __webpack_require__) { eval(` exports = module.exports = __webpack_require__("./node_modules/css-loader/dist/runtime/api.js")(false)); exports.push([module.i, \`body { width: 100%; height: 100vh; background-color: orange; },"\`] `); } } ]);
我们再看下 dist/bundle.js
方便理解,我把大部分代码和注释都删掉了
原理很简单,就是利用的 jsonp 的实现原理加载模块,只是在这里并不是从 server 拿数据而是从其他模块中
window
webpackJsonp
__webpack_require__.e(0)
requireEnsure
script
webpackJsonp.push
webpackJsonpCallback
(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[moduleId] = moreModules[moduleId]; } } if (parentJsonpFunction) parentJsonpFunction(data); while (resolves.length) { // 执行所有 promise 的 resolve 函数 resolves.shift()(); } } function jsonpScriptSrc(chunkId) { return __webpack_require__.p + '' + ({}[chunkId] || chunkId) + '.bundle.js'; } function __webpack_require__(moduleId) { // ... } __webpack_require__.e = function requireEnsure(chunkId) { var promises = []; // ... var script = document.createElement('script'); var onScriptComplete; script.charset = 'utf-8'; script.timeout = 120; script.src = jsonpScriptSrc(chunkId); onScriptComplete = function(event) { // 处理异常,消除副作用 // ... }; var timeout = setTimeout(function() { onScriptComplete({ type: 'timeout', target: script }); }, 120000); script.onerror = script.onload = onScriptComplete; document.head.appendChild(script); // ... // 动态加载模块 return Promise.all(promises); }; var jsonpArray = (window['webpackJsonp'] = window['webpackJsonp'] || []); // 重写数组 push 方法 jsonpArray.push = webpackJsonpCallback; jsonpArray = jsonpArray.slice(); for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]); return __webpack_require__((__webpack_require__.s = 0)); })({ './src/index.js': function(module, exports, __webpack_require__) { eval(` const css = __webpack_require__.e(0).then(__webpack_require__.t.bind(null, "./src/style/index.css", 7)) const a = 100; console.log(a, css) `); }, 0: function(module, exports, __webpack_require__) { eval(`module.exports = __webpack_require__("./src/index.js");`); } });
我们用 webpack-chain 来写 webpack 的配置,原因是 webpack-chain 的方式更加灵活
官方解释
webpack-chain 尝试通过提供可链式或顺流式的 API 创建和修改 webpack 配置。API 的 Key 部分可以由用户指定的名称引用,这有助于跨项目修改配置方式的标准化。
webpack-chain
API
Key
const path = require('path'); const rimraf = require('rimraf'); const Config = require('webpack-chain'); const config = new Config(); const resolve = src => { return path.join(process.cwd(), src); }; // 删除 dist 目录 rimraf.sync('dist'); config // 入口 .entry('src/index') .add(resolve('src/index.js')) .end() // 模式 // .mode(process.env.NODE_ENV) 等价下面 .set('mode', process.env.NODE_ENV) // 出口 .output.path(resolve('dist')) .filename('[name].bundle.js'); config.module .rule('css') .test(/\.css$/) .use('css') .loader('css-loader'); module.exports = config.toConfig();
至此课时 1 已经结束了,我们主要做了以下事情
学习一个工具我们不仅要看懂它的配置,还要对它的原理一起了解,只有学到框架的精髓,我们才能应对如今大前端如此迅猛的发展。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
课题 1: js 是如何引用 css 的?
css 并不能被 webpack 识别,但是可以通过 loader 来将 css 转换成 js
可以分为以下几步实现
webpack 基础配置
需要的依赖包
package.json
webpack 基础配置
webpack.config.js
css 引入到 js
src/index.js
测试 css
src/index.css
解析 bundle 如何加载模块
我删掉了一些注释跟一些干扰内容,这样看起来会更清晰一点
bundle
是一个立即执行函数,可以认为它是把所有模块捆绑在一起的一个巨型模块。webpack
将所有模块打包成了bundle
的依赖,通过一个对象注入0 模块
就是入口webpack
通过__webpack_require__
引入模块__webpack_require__
就是我们使用的require
,被webpack
封装了一层dist/bundle.js
动态 import 加载原理
如果我们把 index.js 的 require 改成 import 会发生什么?
我们知道
import
跟require
的区别是,import
是动态加载只有在用到的时候才会去加载,而require
只要声明了就会加载,webpack
遇到了require
就会把它当成一个模块加载到bundle
的依赖里那么问题来了,如果我们使用了 import 去引用一个模块,它是如何加载的呢?
require 改成 import()
src/index.js
动态加载打包结果
除了正常的
bundle
之外,我们还可以看见一个0.boundle.js
0.boundle.js
就是我们的动态加载的index.css
模块动态模块
0.boundle.js
这个文件就是把我们
import
的模块放进了一个单独的js
文件中动态模块加载逻辑
我们再看下 dist/bundle.js
方便理解,我把大部分代码和注释都删掉了
原理很简单,就是利用的 jsonp 的实现原理加载模块,只是在这里并不是从 server 拿数据而是从其他模块中
window
上注册一个webpackJsonp
数组,window['webpackJsonp'] = window['webpackJsonp'] || []import
时,webpack
会调用__webpack_require__.e(0)
方法,也就是requireEnsure
webpack
会动态创建一个script
标签去加载这个模块,加载成功后会将该模块注入到webpackJsonp
中webpackJsonp.push
会调用webpackJsonpCallback
拿到模块__webpack_require__
获取模块使用 webpack-chain 重写上面配置
我们用 webpack-chain 来写 webpack 的配置,原因是 webpack-chain 的方式更加灵活
官方解释
课时 1 小结
至此课时 1 已经结束了,我们主要做了以下事情
学习一个工具我们不仅要看懂它的配置,还要对它的原理一起了解,只有学到框架的精髓,我们才能应对如今大前端如此迅猛的发展。
The text was updated successfully, but these errors were encountered: