如何通过webpack 实现在 HTML,CSS, JS 中共享变量

4,329 阅读2分钟

主要参考原文链接: www.freecodecamp.org/news/how-to…

概述

项目中通常会需要统一设置样式或者根据某种情况来定 width 和 height, 如何实现在 HTML,CSS, JS 中都能访问到的所谓共享变量呢? 其实都归功于 webpack

作者在阅读了这篇文章之后发现了使用JS 操作 CSS 代价十分昂贵, 会减慢 react 应用的渲染, 主要原因是在 react app 中, react-with-styles使用 runtime 的样式化后的组件会额外生成两个 Context.Consumer以及一个 Provider, 而这些额外的组件使得 CSS 可以监听到某些 JS 事件或者获取变量去更新样式

而静态的 CSS 不会

所以在少部分使用时还好, 但是如果是大规模使用, 比如在 table 中, 就会使得两者的性能差距变大. 但是呢, 谁不想用静态呢? 那不是产品经理有需求, 要动态的去更改啊.

以下方案就是避免了一部分情况下的 JSTOCSS 但并不是所有, 比如用户点击之后对 CSS 进行修改, 这时其实也尽量少的更改 CSS , 而是给组件添加 className, 那样至少省去了 CSS 树的重新构建过程.

设置 app

老样子

  1. yarn init -y
  2. 安装打包工具 webpackyarn add -D webpack webpack-cli
  3. 编辑 package.json 文件
{
    "script": {
        "build": "webpack"
    }
}
  1. 创建 globals.js文件, 里面包含了我们需要跨文件类型去获取的变量
module.exports = {
    myTitle: 'Hello dev.!',
    myColor: '#42ff87'
}
  1. 创建 webpack.config.js打包配置文件
module.exports = {
    entry: __dirname + '/app/index.js',
    output: {
        path: __dirname + '/dist',
        filename: 'bundle.js'
    }
}
  1. 创建一个 app文件夹, 包含 index.html, index.js.文件目录结构如下:
|-- node_modules/
|-- package.json
|-- webpack.config.js
|-- globals.js
|-- app/
	|-- index.html
	|-- index.js

通过插件html-webpack-plugin渲染 html

先在 index.html中写些模板代码, 添加进变量 myTitle

<html lang="en">
<head>
  <title>Webpack shared variables!</title>
</head>
<body>
  <h1><%= myTitle %></h1>
</body>
</html>

安装html-webpack-plugin,

yarn add -D html-webpack-plugin

配置 webpack

const HTMLWebpackPlugin = require('html-webpack-plugin')
const globals = require('./globals.js')

module.exports = {
    // 之前配置的 entry, output 等
    plugins: [
        new HTMLWebpackPlugin({
            template: 'app/index.html',
            templateParameters: globals // 这一步就是注入的变量, 会从这里面拿
        })
    ]
}

执行yarn build就会发现生成的 index.html 中的 myTitle就被替换成了Hello dev.!. 其本质原理其实就是字符串模板.

在 js 中使用变量

这是最基本的了.

import globals from '../globals.js'

document.write(
`<pre>
    ${JSON.stringify(globals, null, 2)}
</pre>`
)
/** 
{
   "myTitle": "Hello dev.to !",
   "myColor": "#42ff87"
}
*/

CSS 中的变量

其实在 CSS 中是无法直接使用全局变量的, 需要用到 SASS. 不过浏览器不认识 sass 这个格式, 需要使用几个 loader, 将其转换成 css.yarn add -D sass-loader css-loader style-loader

app/style.scss中写以下内容, 注意我们使用的是 scss 格式, 它与 sass 的唯一区别就是加不加括号

scss

h1 {
    color: $myColor
}

sass

h1
    color: $myColor

但是因为 scss 兼容所有 css3 以及本身就是 sass3 的新语法, 所以也支持 sass-loader, 所以在项目中一般都使用 scss

接下来需要将变量注入进去. sass-loader有一个prependData的属性, 不过接受的是一个字符串而不是变量的格式, 比如$myColor: red; myTitle: '...'

module.exports = {
    module: {
        rules: [
            {
                test: /\.s(ac)ss$/i,
                use: [
                    "style-loader", // 用于从 js 的字符串创建<style>DOM节点
                    "css-loader", // 将 css 转为 CommonJS
                    {
                        loader: "sass-loader", // 将 Sass 转为 CSS
                        options: {
                            prependData: "$myColor: '#42ff87'"
                        }
                    }
                ]
            }
        ]
    }
}

如果像把 css 单独抽出来的话可以使用 mini-css-extract-plugin, yarn add -D mini-css-extract-plugin安装之后, 将 style-loader 替换成该插件的 loader 即可

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
    module: {
        rules: [
            {
                test: /\.s(ac)ss$/i,
                use: [
                    MiniCssExtractPlugin.loader, // 用于从 js 的字符串创建<style>DOM节点
                    "css-loader", // 将 css 转为 CommonJS
                    {
                        loader: "sass-loader", // 将 Sass 转为 CSS
                        options: {
                            prependData: "$myColor: '#42ff87'"
                        }
                    }
                ]
            }
        ]
    }
}