如何使用webpack和Vue将页面大小增加1500%

Avatar of Burke Holland
Burke Holland

DigitalOcean为您的每个旅程阶段提供云产品。立即开始使用200美元免费信用额度!

免责声明:本文主要为讽刺。我不认为我比你更优秀,因为我曾经写过一些TypeScript,也不认为让网页变得更大是一件好事。请随意曲解这些观点以最大化点击量。

你知道,有很多文章告诉你如何减小页面大小:优化图片,删除多余的CSS规则,使用框架集在Dreamweaver中重写整个页面。看,沃尔玛刚刚将其页面大小减少了一些数字,或多或少。

我们缺少的是足够多的文章向您展示如何*增加*页面大小。事实上,我唯一能找到的文章是来自Geek Squad的这篇文章,结果是关于放大字体大小的。这是一个好的开始,但我认为我们可以做得更好。

增加一些重量

现在,你为什么要增加页面大小?对于低带宽连接的用户来说,这不是一件好事吗?好吧,有几个极好的且绝非牵强的理由,这里列举了三个,因为三个一组的东西更令人满意

  1. 您拥有千兆位连接并且住在田纳西州,因此当然其他每个人都比您情况更好。
  2. 浏览器会进行缓存,这很愚蠢。这意味着您只需下载一次网站。别再抱怨了。这是第一世界的问题。
  3. 您不在乎是否有人访问您的网站,因为您,“工作是为了生活,而不是为了工作而生活”。

如果这些完全相关的理由中的任何一个引起您的共鸣,我想向您展示我是如何将我的CSS大小增加了1500%——您也可以做到,只需一个简单的webpack技巧。

一个奇怪的技巧

这一切都始于我决定将我的退休计划项目The Urlist重构到Bulma CSS框架

该网站的原始版本都是手工编写的,我的Sass看起来像一集《囤积者》节目。

“Burke,你不需要13种不同的.button样式。为什么不选择一种并删除其他12种,这样你就有地方睡觉了?”

Bulma还包含诸如模态之类的功能,我使用第三方Vue组件来创建这些功能。

它还有一个汉堡菜单,因为众所周知,如果没有汉堡,网站就不可能成功。

听着,我并没有制定规则。这就是商业运作方式。

我对结果非常满意。Bulma样式很犀利,布局系统也很容易学习。就好像某个地方的人了解CSS并且也不讨厌我。如今,这两种情况很难同时出现。

经过几周的重构(在此期间我会问自己,“你在做什么?!网站已经可以工作了!”),我终于完成了。顺便说一句,下次你想重构某些东西时,不要这样做。放着它不管。如果你不为下一代留下任何技术债务,他们会非常无聊,这将归咎于你。

当我构建项目时,我注意到了一些奇怪的事情:我的CSS大小增加了相当多。我手工制作的怪物只有30KB(gzip压缩后),重构后增加到了260KB

更糟糕的是,Vue CLI一直在教训我……

当然,我忽略了它。我不接受机器人的指令。

我所做的是部署它。到生产环境。在互联网上。因为我不会花费所有这些时间进行重构而不进行部署。是的,沉没成本等等,但如果我比你的逻辑谬误海报更务实,请原谅我。我只想说,我参加了派对,我不会在没有欢呼声的情况下回家。

然后我转到Twitter,向漠不关心的群众宣布我的成就。就像人们通常做的那样。

此后不久,创建Bulma(并且显然喜欢龙珠)的Jeremy Thomas做出了回应。而且速度很快。好像每当一个白痴发推文时,就会发出一个蝙蝠信号。

重复的样式?13次?什么是命名空间?那是π符号还是Jeremy Thomas的自定义徽标?

就在那一刻,我意识到自己完全不知道自己在做什么。

放下Sass,慢慢后退

我首先承认自己对CSS不太了解,对Sass更是知之甚少。明白了吗?对Sass知之甚少?算了吧。我不想听到你的可怜的笑声。

当我设置我的Vue CLI项目以使用Bulma时,我创建了一个src/styles文件夹并在其中放置了一个bulma-but-not-all-of-bulma-only-some-of-it.scss文件。他们说命名很难,但我不知道为什么。

该文件导入我想使用的Bulma部分。它是Bulma,但不是全部。只是一部分。

@import "bulma/sass/utilities/_all.sass";
@import "bulma/sass/base/_all.sass";

@import "bulma/sass/form/shared.sass";
@import "bulma/sass/form/input-textarea.sass";

// etc...

然后我将该文件导入到一个自定义Sass文件中,我将其命名为……site.scss。我喜欢保持简单。

@import "./bulma-but-not-all-of-bulma-only-some-of-it.scss";

html,
body {
  background-color: #f9fafc;
}

// etc...

我想全局导入这些文件,以便可以在每个组件中使用它们。并且我想以正确的方式进行操作;规范的方式。我认为从我愿意将2+MB的CSS部署到生产环境中可以清楚地看出,我喜欢以“正确的方式”做事。

我阅读了Sarah Drasner撰写的这篇优秀的博文,名为“如何在Vue应用程序中的每个组件中导入Sass文件”。她展示了如何通过vue.config.js文件修改webpack构建过程来实现此目的。

module.exports = {
  css: {
    loaderOptions: {
      sass: {
        data: `@import "@/styles/site.scss";`
      }
    }
  }
}

我无法理解的是,这会将Sass导入到Vue应用程序中的每个组件中。你知道,**就像博客文章标题字面上所说的那样**。这也是我最终得到一堆带有data-v-属性选择器的重复样式的原因。我要感谢作用域样式。

Vue如何处理`scoped`

Vue允许您将样式“作用域”到组件中。这意味着样式仅影响其所在的组件,而不是页面的其余部分。没有可以执行此操作的魔法浏览器API。Vue通过在元素和选择器中动态插入data-属性来实现此目的。例如,以下内容

<template>
  <button class="submit">Submit</button>
<template>

<style lang="scss" scoped>
.submit {
  background-color: #20ae96;
}
</style>

…将变成以下内容

<button class="submit" data-v-2929>Submit</button>

<style>
.submit[data-v-2929] {
  background-color: #20ae96;
}
</style>

该动态数据标签也会添加到组件中的每个子元素中。因此,此组件的每个元素和每个样式在运行时都将具有data-v-2929

如果您将包含实际样式的Sass文件导入到您的组件中,Vue(通过webpack)将提取这些样式并使用该动态data-属性为其“命名空间”。结果是,如果您在应用程序中包含13次Bulma,并在其前面加上一堆data-v怪异内容。

但这引发了一个问题:如果webpack在每个组件中呈现CSS,为什么要使用vue.config.js方法?一句话:**变量**。

变量共享问题

你不能在一个组件中定义一个 Sass 变量,然后在另一个组件中引用它。这样做也很难管理,因为你将在各处定义和使用变量。只有我才会写这样的代码。

而你,另一方面,可能会将所有变量放在一个 variables.scss 文件中。然后,每个组件都会引用这个变量的中心存储库。在每个组件中都导入变量文件是多余的。它也过于繁琐。而且不必要。以及冗长。

这正是 Sarah 的文章要解决的问题:将 Sass 文件导入项目中的每个组件。

将像变量这样的东西导入到每个组件中是可以的,因为变量不会被渲染。如果你导入了 200 个变量,而只引用了其中一个,那又有什么关系呢?这些变量在渲染后的 CSS 中并不存在。

例如,这样

<style lang="scss" scoped>
$primary: #20ae96;
$secondary: #336699;

.submit {
  background-color: $primary
}
</style>

…将变成以下内容

<style>
.submit[data-v-2929] {
  background-color: #20ae96;
}
</style>

所以,这里实际上有两个问题

  1. Bulma 需要是全局的。
  2. Bulma 的变量应该可以从组件中访问。

我们需要巧妙地结合 Sarah 的技术,以及一些关于 Bulma 结构的专有知识。

在 Vue 中使用 Bulma

我们将通过在 src/styles 目录中创建三个文件来实现这一点,并尽可能减少重复。

variables.scss:此文件将用于引入 Bulma 的变量并覆盖/定义你自己的变量。请注意,你必须包含以下三个文件才能获取 Bulma 的所有变量。并且它们必须按照此顺序排列……

// Your variables customizations go up here

// Include Bulma's variables
@import "bulma/sass/utilities/initial-variables.sass";
@import "bulma/sass/utilities/functions.sass";
@import "bulma/sass/utilities/derived-variables.sass";

bulma-custom.scss:此文件用于引入你需要的 Bulma 部分。它应该引用 variables.scss 文件。

@import "./variables.scss";

/* UTILTIES */
@import "bulma/sass/utilities/animations.sass";
@import "bulma/sass/utilities/controls.sass";
@import "bulma/sass/utilities/mixins.sass";

// etc...

site.scss:此文件引入 bulma-custom.scss 文件,并且也是你在整个项目中使用的全局样式的定义位置。

@import url("https://use.fontawesome.com/releases/v5.6.3/css/all.css");
@import "./bulma-custom.scss";

html,
body {
  height: 100%;
  background-color: #f9fafc;
}

// etc...

site.scss 文件导入你的 main.js 文件。或者在我的例子中,是 main.ts。使用 TypeScript 能让我比你更优秀吗?是的。是的,的确如此。

import Vue from "vue";
import App from "./App.vue";
import router from "./router";

// import styles
import "@/styles/site.scss";

这使得我们使用的所有 Bulma 部分都可以在每个组件中使用。它们是全局的,但只包含一次。

根据 Sarah 的文章,将 variables.scss 文件添加到 vue.config.js 文件中。

module.exports = {
  css: {
    loaderOptions: {
      sass: {
        data: `@import "@/styles/variables.scss";`
      }
    }
  }
}

这样一来,你就可以从任何 .vue 组件中引用任何 Bulma 变量或你自己的变量。

现在,你拥有了两个世界中最好的:Bulma 可全局使用,并且你仍然可以在每个组件中访问所有 Bulma 变量。

现在 CSS 的总大小?大约缩小了 1,500%……

去你的,沃尔玛。

通过 PR 赎回

为了赎回我自己,我向 Bulma 文档提交了一个 PR,其中介绍了如何在 Vue CLI 项目中自定义 Bulma。这是我对在 Twitter 上发言并使 Bulma 看起来像是问题(而实际上 Burke 才是问题)的一种悔过行为。

你会认为到目前为止我已经弄清楚了:Burke 永远是问题所在。