webpack打包css js 成内联样式

2,271 阅读1分钟

对外提供一个html,用户点击执行。产品只要对外提供一个html并且希望js做到加密。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* 样式 */
  </style>
</head>

<body>
  <div>--------</div>
</body>
<script>
  // 内容
</script>

</html>

写好后使用gulp压缩加密

gulp实现

gulp.js

const gulp = require('gulp');
const htmlmin = require('gulp-html-minifier-terser');

const options = {
    removeComments: true,//清除HTML注释
    collapseWhitespace: true,//压缩HTML
    minifyJS: true,//压缩页面JS
    minifyCSS: true,//压缩页面CSS
};
gulp.task('minify', () => {
    return gulp.src('*.html')
        .pipe(htmlmin(options))
        .pipe(gulp.dest('dist'));
});

// 默认任务
gulp.task('default', gulp.series('minify'));

感觉使用gulp总觉得太low。于是查找使用webpack

webpack做法

首先对文件进行拆分成 index.html index.js index.css。开始打包

const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

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

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    entry: {
        entry: './src/index.js'
    },
    output: {
        clean: true, // 先清空output
        //输出的路径,用了Node语法
        path: path.resolve(__dirname, 'dist'),
        //输出的文件名称
        filename: 'index.js'
    },
    externals: {},
    mode: "production",
    optimization: {
        minimizer: [
            new UglifyJsPlugin({
                uglifyOptions: {
                    // 删除注释
                    output: {
                        comments: false,
                    },
                    compress: {
                        drop_console: true, // 删除所有调式带有console的
                        drop_debugger: true,
                        pure_funcs: ['console.log'] // 删除console.log
                    }
                },
            })
        ]
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader, // 提取css生产css文件
                    {
                        loader: 'css-loader',   // 放在后面的先被解析
                        options: {
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new htmlPlugin({
            minify: {
                removeComments: true,//清除HTML注释
                collapseWhitespace: true,//压缩HTML
                minifyJS: true,//压缩页面JS
                minifyCSS: true,//压缩页面CSS
            },
            hash: false,
            inject: 'body', // js插入到body下面
            template: './src/index.html'
        }),
        new MiniCssExtractPlugin(), // 提取css生成文件
    ],
    devServer: {
        static: {
            directory: path.resolve(__dirname, 'dist')
        },
        // hot: false,
        compress: true,
        open: true,
        liveReload: true, // 只监听js变化 当检测到文件更改时,开发服务器将重新加载/刷新页面。devServer.hot选项必须禁用或devServer.watchFiles选项必须启用, 以便liveReload生效。禁用devServer.liveReload设置为false来重新加载:
        port: 8086
    }
}

这样打包出来后是通过src引入的。不符合我们要求。

自己写plugin

plugin.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
class MyPlugin {
    constructor({ match }) {
        this.match = match;
    }
    processTags(data, compilation) {
        let headTags = [];
        let bodyTags = [];
        console.log(data.headTags);
        console.log(data.bodyTags);
        console.log('--------------');
        data.headTags.forEach((headTag) => {
            // js 放到下面
            if (headTag.tagName === 'script') {
                bodyTags.push(this.processTag(headTag, compilation))
            } else {
                headTags.push(this.processTag(headTag, compilation))
            }
        });
        data.bodyTags.forEach((bodyTag) => {
            bodyTags.push(this.processTag(bodyTag, compilation))
        });
        return {
            ...data,
            headTags,
            bodyTags
        }
    }

    //处理每个link和script标签。
    processTag(tag, compilation) {
        let newTag, url;
        // if (tag.tagName === "link" && this.match.includes(tag.attributes.href)) {
        if (tag.tagName === "link") {
            newTag = {
                tagName: "style",
                attributes: {
                    type: "text/css"
                }
            }
            url = tag.attributes.href;
        }
        // if (tag.tagName === "script" && this.match.includes(tag.attributes.src)) {
        if (tag.tagName === "script") {
            newTag = {
                tagName: "script",
                attributes: {
                    type: "application/javascript"
                }
            }
            url = tag.attributes.src;
        };
        if (url) {
            // 通过compilation.assets[文件地址]可以获取到每个文件的内容。
            newTag.innerHTML = compilation.assets[url].source();
            delete compilation.assets[url];  // 删除原来的资源,不让生成文件
            return newTag;
        }
        return tag;
    }

    apply(compiler) {
        //    console.log("compiler:", compiler.hooks)
        // 要通过webpack-plugin来实现这个功能
        compiler.hooks.compilation.tap("MyPlugin", (compilation) => {
            // 调用html-webpack-plugin的内部的钩子alterAssetTagGroups。
            HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(
                'MyPlugin', (data, callback) => {
                    data = this.processTags(data, compilation);
                    callback(null, data)
                }
            )
        })
    }
}
module.exports = MyPlugin;

webpack.config.js

const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

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

const MyPlugin = require('./myPlugin');

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    //入口文件的配置项
    entry: {
        entry: './src/index.js'
    },
    //出口文件的配置项
    output: {
        clean: true, // 先清空output
        //输出的路径,用了Node语法
        path: path.resolve(__dirname, 'dist'),
        //输出的文件名称
        filename: 'index.js'
    },
    externals: {},
    mode: "production",
    optimization: {
        minimizer: [
            new UglifyJsPlugin({
                uglifyOptions: {
                    // 删除注释
                    output: {
                        comments: false,
                    },
                    compress: {
                        drop_console: true, // 删除所有调式带有console的
                        drop_debugger: true,
                        pure_funcs: ['console.log'] // 删除console.log
                    }
                },
            })
        ]
    },
    // //模块:例如解读CSS,图片如何转换,压缩
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    // {
                    //     loader: 'style-loader',  // 把css放到js里面
                    // },
                    MiniCssExtractPlugin.loader, // 提取css生产css文件
                    {
                        loader: 'css-loader',   // 放在后面的先被解析
                        options: {
                        }
                    }
                ]
            }
        ]
    },
    //插件,用于生产模版和各项功能 多个插件,所以是数组
    plugins: [
        new htmlPlugin({
            minify: {
                removeComments: true,//清除HTML注释
                collapseWhitespace: true,//压缩HTML
                minifyJS: true,//压缩页面JS
                minifyCSS: true,//压缩页面CSS
            },
            hash: false,
            inject: 'body', // js插入到body下面
            template: './src/index.html'
        }),
        new MiniCssExtractPlugin(), // 提取css生成文件
        new MyPlugin({ // 变成内联
          match: ['index.js']
        }),

    ],
    //配置webpack开发服务功能
    devServer: {
        static: {
            directory: path.resolve(__dirname, 'dist')
        },
        // hot: false,
        compress: true,
        open: true,
        liveReload: true, // 只监听js变化 当检测到文件更改时,开发服务器将重新加载/刷新页面。devServer.hot选项必须禁用或devServer.watchFiles选项必须启用, 以便liveReload生效。禁用devServer.liveReload设置为false来重新加载:
        port: 8086
    }
}