webpack 资源内联

作者: shaokang 时间: January 4, 2022字数:2860

前言

前阵子发现项目中所有的资源最后都会编译内联到 html 中,内联资源是写的一个插件实现的,而该插件很久远不再维护,所以在网上找了些类似插件,这里记录下。

资源内联

资源内联(inline resource),就是将一个资源以内联的方式嵌入进另一个资源里面,即将 css 样式和 js 通过 style、script 标签直接签入到页面中。 这样做的好处是可以减少 HTTP 的请求数,当然如果你的网站有使用 HTTP2 这点的意义可能不会那么大。

CSS 内联

通常情况下,为了更好的加载体验,我们会将打包好的 CSS 内联到 HTML 头部,这样 HTML 加载完成 CSS 就可以直接渲染出来,避免页面闪动的情况。那么 CSS 内联如何实现呢? CSS 内联的核心思路是:将页面打包过程的产生的所有 CSS 提取成一个独立的文件,然后将这个 CSS 文件内联进 HTML head 里面。这里需要借助 mini-css-extract-plugin 和 html-inline-css-webpack-plugin 来实现 CSS 的内联功能。

// webpack.config.js

const path = require('path');

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js',
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name]_[chunkhash:8].js',
    },
    mode: 'production',
    plugins: [
        new MiniCssExtractPlugin({
            filename: '[name]_[contenthash:8].css',
        }),
        new HtmlWebpackPlugin(),
        new HTMLInlineCSSWebpackPlugin(),
    ],
};

另外还可以使用 style-loader

module: {
    rules: [
        {
            test: /.css$/,
            use: [
            {
                loader: 'style-loader',
                options: {
                    injectType: 'singletonStyleTag', // 将所有style标签合并成一个
                }
            }
            'css-loader'
            'postcss-loader',
            'sass-loader'
            ]
        },
    ]
}

style-loader VS html-inline-css-webpack-plugin

  1. style-loader 是 css-in-js,需要加载 js 后才能写入到 style 中,有一定的延迟性。即编译后的文件 HEAD 中并没有直接嵌入 style 标签,而是通过 JS 来实现的,所以需要将加载 JS 内容才能将样式写入 style。
  2. html-inline-css-webpack-plugin 是将 css 提取出来,再写入到 html 中,html 网页源代码中已经内联好 css 了,没有延迟性了 请求层面:减少 HTTP 网络请求数

小图片和字体内联可以使用 url-loader

JS 内联

  1. react-dev-utils/InlineChunkHtmlPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');

module.exports = {
    // ...
    output: { filename: 'client-bundle.js' },
    plugins: [
        new HtmlWebpackPlugin(),
        new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/client-bundle/]),
    ],
    // ...
};

注意:必须使用 html-webpack-plugin@4 及其以上的版本。

  1. script-ext-html-webpack-plugin
module.exports = {
    // ...
    plugins: [
        new HtmlWebpackPlugin(),
        new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/\*.js$/]),
    ],
    // ...
};

类似的插件还有很多,可以去 github 上找。

html-webpack-inline-source-plugin

这个插件能实现 CSS 和 JS 均内联的效果,但已不再维护了。

plugins: [
    new HtmlWebpackPlugin({
        inlineSource: '.(js|css)$', // embed all javascript and css inline
    }),
    new HtmlWebpackInlineSourcePlugin(),
];

自己实现一个内联插件

先了解下 html-webpack-plugin 插件。 其中关键的 inject 配置。可以选择 false,即不将资源注入到模板,这样就能自行实现一个插件来注入模板中了。

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: 'index.js',
    output: {
        path: __dirname + '/dist',
        filename: 'index_bundle.js',
    },
    plugins: [
        new HtmlWebpackPlugin({
            inject: false,
        }),
    ],
};