共计 4415 个字符,预计需要花费 12 分钟才能阅读完成。
对于款式编译
因为 webpack 编译的思维是万无皆可 JS,意旨所有 web 我的项目关联的资源文件,都能够通过 js 关联起来。然而又因为图片,款式这些原本和 js 八竿子打不到一起的,所以就有了各种 loader 来解决他们的关联性问题;
说到 webpack 的款式编译,总有几个 loader 是不能错过的,比方 less-loader, css-loader,style-loader, 轻易上一段罕用配置:
const lessLoader = {
test: /\.less$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {modules: true,},
},
'less-loader',
],
}
以上文件就是通知 webpack,在遇到文件名以.less 结尾的文件,先用 less-loader 编译,再用 css-loader 编译,最初用 style-loader,已经我是用这样一段 js 伪代码来概述的:
// 伪代码
const res = styleLoader(cssLoader(lessLoader('xxx.less')));
其实这个伪代码,一点都不谨严.
都是 loader,但作用却天壤之别
style-loader
其实与 css-loader
, less-loader
的作用是有区别的,后者其实承当的是模块化与语法转译这一块;而 style-loader
这一类(还有罕用的 mini-css-extract-plugin)承当的是粘结剂性能,就是将 js 中的 css 加载到 html 中,从而使款式失效;
随便谨严一点的伪代码应该这样写:
const cssContent = cssLoader(lessLoader('xxx.less'));// 通过 styleTag 插入 css 字符串到 head 中
styleLoader(cssContent, document.head);
如同文章写到这里就应该完结了,但实际上好戏才开始。
已经我认为,style-loader
是在构建时,就将款式插入到了 html 中,但实际上我错了,而且这一错就是五年 (已经你认为的,不过是你的无知:送给本人), 正确的答案是 css 被构建到了 js 文件中,而后在 js 文件加载时,通过style-loader
提供的办法将其加载到 html 中。
简略来讲,已经我认为这个 loader 是个构建时,但他其实是一个运行时。
怎么判断呢,很简略,就像如何判断一个网站是否是服务端渲染一样,看网站首页申请获取的 html 文件是否含款式(也能够间接通过 source 面板查看 html 文件, 不是 elements)。
之所以会产生这个误判,是我间接平移了 mini-css-extract-plugin
的构建思维,这个 plugin 就剥离了 JS 中的款式,造成了一个新的文件,而后再把款式地址插入到 html 头中,这是个完完全全的构建时。
而最近为什么会忽然关注到这个点,是因为咱们在调一个 微组件
的计划,在组件胜利加载时,发现款式失落, 看看下图的惨不忍睹:
通过 debug,发现款式的确被打包进了文件,只是没有被加载到 style 标签中,第一直觉就是短少 loader,而后查看构建工具,发现款式编译配置只到了 css-loader
这一级,短少style-loader
。
从构建后果看款式加载过程
如果到这文章就完结了,仿佛就太不像我了,毕竟刨根问底(xuxudaodao)的我才是真的我. 接下来,通过一段实例代码,来看 webpack 构建,是怎么实现款式加载的。
示例代码:
// style.less 代码
@font-size: 28px;
.Demo {
box-sizing: border-box;
:global {
.demo-title {font-size: @font-size;}
}
}
import React from 'react';
// 引入款式
import style from './style.less';
export default function Demo() {
return (<div className={style.Demo}>
<h3 className="emo-title">this is a demo</h3>
</div>
);
}
而后通过 webpack,采纳 style-loader 的形式构建,为了不便浏览,没有做代码压缩和美化。
而后从入口能够看见款式引入是这样的:
// 正文无用代码有删减
__webpack_require__.d(__webpack_exports__, "default", function() {return Demo;});
var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
// 引入款式
var _style_less__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/demo/style.less");
var _style_less__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_style_less__WEBPACK_IMPORTED_MODULE_1__);
function Demo() {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {className: _style_less__WEBPACK_IMPORTED_MODULE_1___default.a.Demo}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h3", {className: "emo-title"}, "this is a demo"));
}
能够看见,在入口文件,有一个从 ./src/demo/style.less
模块的款式引入,并赋值给了 _style_less__WEBPACK_IMPORTED_MODULE_1___default
变量;
而后顺藤摸瓜,持续看一下 style.less 模块长什么样:
// "./src/demo/style.less" 模块
function(module, exports, __webpack_require__) {var api = __webpack_require__("../../../../.def/def_modules/.builders/@ali/builder-cook/node_modules/_style-loader@1.3.0@style-loader/dist/runtime/injectStylesIntoStyleTag.js");
var content = __webpack_require__("../../../../.def/def_modules/.builders/@ali/builder-cook/node_modules/_css-loader@1.0.1@css-loader/index.js?!../../../../.def/def_modules/.builders/@ali/builder-cook/node_modules/_postcss-loader@3.0.0@postcss-loader/src/index.js?!../../../../.def/def_modules/.builders/@ali/builder-cook/node_modules/_less-loader@6.2.0@less-loader/dist/cjs.js?!./src/demo/style.less");
content = content.__esModule ? content.default : content;
if (typeof content === 'string') {content = [[module.i, content, '']];
}
var options = {};
options.insert = "head";
options.singleton = false;
var update = api(content, options);
module.exports = content.locals || {};}
这这一块的代码就能够看出,这一个模块是一个承上(css 引入)启下(插入 html);
承上通过从 less-loader/dist/cjs.js?!./src/demo/style.less
这个模块引入, 而插入 html 则是通过从 injectStylesIntoStyleTag
导入了一个办法,从办法名就能够晓得他的作用就是通过 style 标签插入 css 款式.
这外面还有一个点,就是最初的导出,模块最初将 content.locals 导出,持续依据线索去看看 content 到底是什么:
function(module, exports, __webpack_require__) {exports = module.exports = __webpack_require__("../../../../.def/def_modules/.builders/@ali/builder-cook/node_modules/_css-loader@1.0.1@css-loader/lib/css-base.js")(false);
exports.push([module.i, "._1rfoVjSya7b-iuQB2_qKPh {\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n}\n._1rfoVjSya7b-iuQB2_qKPh .demo-title {\n font-size: 28px;\n}\n", ""]);
exports.locals = {"Demo": "_1rfoVjSya7b-iuQB2_qKPh"};
}
通过下面的代码,就能够看出 exports.locals
的作用就是 css 的模块化
至此,水落石出 ….
写在最初
我仿佛特地享受这种顺藤摸瓜的前端 (ruozhi) 侦探感觉, 这让以前对我来说的一个黑盒被关上了,最初还是那句话,前端外面真的没什么黑魔化,根本就是红宝书外面的常识,只有能静下心来细品: 魔法究竟只是一个特地好的想法而已。