在HTTP/2中管理CSS和JS

2019-03-28 10:18:05 浏览数 (1)

在HTTP/2的时代里,在你的网站里发布CSS和JS跟以前大不相同了,以下是我实践的一份建议。

我们听说HTTP/2已经很多年了,我们也写过一些相关的博客。但是我们并没有怎么使用它。直到现在,在一些最近的项目里,我把使用HTTP/2设定为一个目标,并且想出怎样最好的使用多路复用特性。这篇文章并不是来说明你为什么需要使用HTTP/2,而是讨论我是怎么在这种规范的转变中管理CSS和JS的。

拆分CSS

这是我们多年以来的最佳实践的反例。但是为了利用多路复用特性,最好把你的CSS拆分到更小的文件里,这样在每个页面中只加载需要的CSS。像下面这个例子这样:

代码语言:javascript复制
<html>
<head>
  <!-- 每个页面都使用的全局CSS, 头部/底部/其他 -->
  <link href="stylesheets/global/index.css" rel="stylesheet">
</head>
<body>

  <link href="stylesheets/modules/text-block/index.css" rel="stylesheet">
  <div class="text-block">
    ...
  </div>

  <link href="stylesheets/modules/two-column-block/index.css" rel="stylesheet">
  <div class="two-column-block">
    ...
  </div>

  <link href="stylesheets/modules/image-promos-block/index.css" rel="stylesheet">
  <div class="image-promos-block">
    ...
  </div>

</body>
</html>

是的,这些都是在标签内部. 但是,不要紧张,在规范中并没说不让这样用。对于每个小的标签块,你的样式可以拆分为只包含对应的CSS。假设你正在使用最近很流行的模块化搭建你的页面,这很容易设置。

管理你的SCSS文件

经过一些试验,这是我最后整理的SCSS文件目录结构:

config 文件夹

我用这个文件夹来设置所用的变量。

这里最主要的文件是_index.scss,它用来输入到其他SCSS文件,这样我可以获取到变量或者mixins。里面是这样的:

代码语言:javascript复制
@import "variables";
@import "../functions/*";
functions 文件夹

这个文件夹自身就完美的解释了它的含义;它包含了自定义的mixinsfunctions(方法),每个文件代表了一个mixins或者function(方法)

global 文件夹

这个文件夹是我在每个页面都有用到的CSS。适用于网站的头部,底部,重置,字体,和其他通用样式。

index.scss如下所示:

代码语言:javascript复制
@import "../config/index";
@import "_fonts.scss";
@import "_reset.scss";
@import "_base.scss";
@import "_utility.scss";
@import "_skip-link.scss";
@import "_header.scss";
@import "_content.scss";
@import "_footer.scss";
@import "components/*";

最后一行是输入到整个组件目录的子文件夹里,在模块化中避免额外的全局样式是个捷径。

modules 文件夹

在我们的HTTP/2设置中这是最重要的文件夹。当我拆分样式到对应的模块,这个文件夹会包含非常非常多的文件。所以一个子文件夹就是一个模块:

然后,每个模块的index.scss就像下面这样:

代码语言:javascript复制
// Pull in all global variables and mixins
@import "../../config/index";

// Pull in all partials in this module's folder
@import "_*.scss";

这样我可以获取到变量和mixins,然后我可以拆分模块的CSS为许多部分,它们组合成一个单独的CSS模块文件夹。

pages 文件夹

事实上这个文件夹跟modules文件夹基本一样,但我用来放页面的特殊样式。这种更细化的模块化在我们这些天做的东西里绝对罕见,但是它很好的把页面的特殊样式拆分出来了。

调整 Blendid

我们这些天做的大多数项目都是用Blendid来构建的。为了获取上述SCSS配置,我需要添加node-sass-glob-importer package。当我安装完成后,我只需要把它添加到Blendid的task-config.js文件中。

代码语言:javascript复制
var globImporter = require('node-sass-glob-importer');

module.exports = {
  stylesheets: {
    ...
    sass: {
      importer: globImporter()
    },
      ...
}

biu的一下,我就搞好了HTTP/2的SCSS配置。

福利: Craft 宏(可以理解为模板的意思)

我们在Viget(作者公司)很长一段时间都主张使用Craft,我就写了一个宏模板来减少这种方式下引入样式的重复性:

代码语言:javascript复制
{%- macro css(stylesheet) -%}
  <link rel="stylesheet" href="/stylesheets{{ stylesheet }}/index.css" media="not print">
{%- endmacro -%}

当我想要引入一个模块的CSS文件夹,只需要这样:

代码语言:javascript复制
`{{ macros.css('/modules/image-block') }}`

这让我在处理站点中的样式关系更简单点。

管理 JS

嗯,就像我处理CSS一样,我希望把JS拆分成模块,这样每个页面只需要加载其所需的JS。接着,使用Blendid 配置,我只需要做一点微调就可以正常工作了。

相对于使用Webpack的require(),我需要使用import()modules/index.js文件就像这样:

代码语言:javascript复制
const moduleElements = document.querySelectorAll('[data-module]');

for (var i = 0; i < moduleElements.length; i  ) {
  const el = moduleElements[i];
  const name = el.getAttribute('data-module');

  import(`./${name}`).then(Module => {
    new Module.default(el);
  });
}

就像Webpack文档中说的:“这个特性在内部依赖Promise。如果你在老式浏览器中使用import(),记得用类似 es6-promise 或者 promise-polyfill 来兼容Promise。”

我安装了es6-promise,并引入到我的app.js文件中,实现自动兼容。

So I can easily drop in the es6-promise polyfill into my main app.js file and have it polyfill automatically:

代码语言:javascript复制
`require('es6-promise/auto');`

是的,你就可以使用在Blendid中提及的方式来生成JS模块。

代码语言:javascript复制
`<div data-module="carousel">`

完美吗?

不,但至少让你知道一种标准的方法来管理你的HTTP/2资源。随着我们思考如何更好的利用HTTP/2来分离代码,我非常期待这份方案会越来越完善。


往期精选文章

ES6中一些超级好用的内置方法

浅谈web自适应

使用Three.js制作酷炫无比的无穷隧道特效

一个治愈JavaScript疲劳的学习计划

全栈工程师技能大全

WEB前端性能优化常见方法

一小时内搭建一个全栈Web应用框架

干货:CSS 专业技巧

四步实现React页面过渡动画效果

让你分分钟理解 JavaScript 闭包



小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。

0 人点赞