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? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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: