怎样实现静态资源合并脚本

wen 实用脚本 30

本文目录导读:

怎样实现静态资源合并脚本

  1. Webpack
  2. 自定义脚本

我来介绍几种实现静态资源合并脚本的方法,包括前端构建工具方案和纯脚本方案。

使用 Gulp 实现资源合并

// gulpfile.js
const gulp = require('gulp');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
const cleanCSS = require('gulp-clean-css');
// 合并并压缩 JavaScript
gulp.task('scripts', function() {
    return gulp.src([
        './src/js/jquery.js',
        './src/js/utils.js',
        './src/js/main.js'
    ])
    .pipe(concat('bundle.min.js'))
    .pipe(uglify())
    .pipe(gulp.dest('./dist/js'));
});
// 合并并压缩 CSS
gulp.task('styles', function() {
    return gulp.src([
        './src/css/reset.css',
        './src/css/common.css',
        './src/css/main.css'
    ])
    .pipe(concat('style.min.css'))
    .pipe(cleanCSS())
    .pipe(gulp.dest('./dist/css'));
});
// 默认任务
gulp.task('default', gulp.parallel('scripts', 'styles'));

使用 Webpack 实现资源合并

// webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
    entry: {
        main: [
            './src/js/jquery.js',
            './src/js/utils.js',
            './src/js/main.js'
        ],
        style: [
            './src/css/reset.css',
            './src/css/common.css',
            './src/css/main.css'
        ]
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: '[name].min.css'
        })
    ],
    optimization: {
        minimize: true
    }
};

纯 Node.js 脚本实现

// merge-assets.js
const fs = require('fs').promises;
const path = require('path');
const { minify } = require('terser');
const CleanCSS = require('clean-css');
class AssetMerger {
    constructor(options = {}) {
        this.sourceDir = options.sourceDir || './src';
        this.outputDir = options.outputDir || './dist';
    }
    // 合并 JavaScript 文件
    async mergeJS(files, outputName) {
        try {
            let combined = '';
            for (const file of files) {
                const filePath = path.join(this.sourceDir, file);
                const content = await fs.readFile(filePath, 'utf-8');
                combined += `\n// Source: ${file}\n${content}`;
            }
            // 压缩代码
            const minified = await minify(combined, {
                compress: true,
                mangle: true
            });
            // 写入文件
            await this.ensureDir();
            const outputPath = path.join(this.outputDir, outputName);
            await fs.writeFile(outputPath, minified.code);
            console.log(`✓ JavaScript 合并完成: ${outputName}`);
            console.log(`  原始大小: ${(Buffer.byteLength(combined) / 1024).toFixed(2)} KB`);
            console.log(`  压缩大小: ${(Buffer.byteLength(minified.code) / 1024).toFixed(2)} KB`);
        } catch (error) {
            console.error('JS合并失败:', error.message);
            throw error;
        }
    }
    // 合并 CSS 文件
    async mergeCSS(files, outputName) {
        try {
            let combined = '';
            for (const file of files) {
                const filePath = path.join(this.sourceDir, file);
                const content = await fs.readFile(filePath, 'utf-8');
                combined += `\n/* Source: ${file} */\n${content}`;
            }
            // 压缩 CSS
            const minified = new CleanCSS().minify(combined);
            if (minified.errors.length > 0) {
                console.error('CSS压缩错误:', minified.errors);
                return;
            }
            // 写入文件
            await this.ensureDir();
            const outputPath = path.join(this.outputDir, outputName);
            await fs.writeFile(outputPath, minified.styles);
            console.log(`✓ CSS 合并完成: ${outputName}`);
            console.log(`  原始大小: ${(Buffer.byteLength(combined) / 1024).toFixed(2)} KB`);
            console.log(`  压缩大小: ${(Buffer.byteLength(minified.styles) / 1024).toFixed(2)} KB`);
        } catch (error) {
            console.error('CSS合并失败:', error.message);
            throw error;
        }
    }
    // 确保输出目录存在
    async ensureDir() {
        try {
            await fs.mkdir(this.outputDir, { recursive: true });
        } catch (error) {
            if (error.code !== 'EEXIST') throw error;
        }
    }
    // 批量处理
    async batchMerge(configs) {
        for (const config of configs) {
            if (config.type === 'js') {
                await this.mergeJS(config.files, config.output);
            } else if (config.type === 'css') {
                await this.mergeCSS(config.files, config.output);
            }
        }
    }
}
// 使用示例
async function main() {
    const merger = new AssetMerger({
        sourceDir: './src',
        outputDir: './dist'
    });
    // 配置合并规则
    const configs = [
        {
            type: 'js',
            files: [
                'js/lib/jquery.min.js',
                'js/lib/bootstrap.min.js',
                'js/utils.js',
                'js/main.js'
            ],
            output: 'scripts.bundle.min.js'
        },
        {
            type: 'css',
            files: [
                'css/bootstrap.min.css',
                'css/font-awesome.min.css',
                'css/style.css',
                'css/custom.css'
            ],
            output: 'styles.bundle.min.css'
        }
    ];
    try {
        console.log('开始合并静态资源...\n');
        await merger.batchMerge(configs);
        console.log('\n✅ 所有资源合并完成!');
    } catch (error) {
        console.error('\n❌ 合并失败:', error.message);
    }
}
// 运行脚本
main();

使用配置文件的高级版本

// merge-config.js
module.exports = {
    // JavaScript 合并配置
    js: {
        bundles: [
            {
                name: 'vendor',
                files: [
                    'js/jquery.min.js',
                    'js/bootstrap.min.js',
                    'js/lodash.min.js'
                ],
                output: 'vendor.bundle.min.js'
            },
            {
                name: 'app',
                files: [
                    'js/utils.js',
                    'js/components.js',
                    'js/app.js'
                ],
                output: 'app.bundle.min.js'
            }
        ],
        // 外部引入的库不合并
        exclude: [
            'js/cdn/**'
        ]
    },
    // CSS 合并配置
    css: {
        bundles: [
            {
                name: 'vendor',
                files: [
                    'css/bootstrap.min.css',
                    'css/font-awesome.min.css'
                ],
                output: 'vendor.bundle.min.css'
            },
            {
                name: 'app',
                files: [
                    'css/layout.css',
                    'css/theme.css',
                    'css/custom.css'
                ],
                output: 'app.bundle.min.css'
            }
        ]
    },
    // 输出目录
    output: {
        dir: './dist',
        // 是否添加版本号
        versioning: true,
        // 版本号生成方式
        versionType: 'timestamp' // 'hash' | 'timestamp' | 'custom'
    }
};

集成到构建流程

// package.json
{
  "scripts": {
    "merge": "node merge-assets.js",
    "watch": "nodemon --watch src --ext js,css --exec \"node merge-assets.js\"",
    "build": "npm run merge && npm run compress-images"
  }
}

使用 HTML 自动注入

// auto-inject.js
const fs = require('fs').promises;
const path = require('path');
class HtmlInjector {
    constructor(options = {}) {
        this.htmlDir = options.htmlDir || './html';
        this.assetsDir = options.assetsDir || './dist';
    }
    async injectBundles(htmlFile, bundles) {
        try {
            const htmlPath = path.join(this.htmlDir, htmlFile);
            let html = await fs.readFile(htmlPath, 'utf-8');
            // 移除旧的引用
            html = html.replace(/<script.*?src=".*?".*?><\/script>/g, '');
            html = html.replace(/<link.*?href=".*?".*?>/g, '');
            // 注入新的合并文件
            if (bundles.js) {
                const jsTags = bundles.js.map(file => 
                    `<script src="${file}"></script>`
                ).join('\n    ');
                html = html.replace('</head>', `    ${jsTags}\n</head>`);
            }
            if (bundles.css) {
                const cssTags = bundles.css.map(file => 
                    `<link rel="stylesheet" href="${file}">`
                ).join('\n    ');
                html = html.replace('</head>', `    ${cssTags}\n</head>`);
            }
            // 写入更新后的 HTML
            await fs.writeFile(htmlPath, html);
            console.log(`✓ HTML 更新完成: ${htmlFile}`);
        } catch (error) {
            console.error('HTML注入失败:', error.message);
        }
    }
}

使用方法

  1. 安装依赖

    npm init -y
    npm install gulp gulp-concat gulp-uglify clean-css --save-dev
    # 或
    npm install webpack webpack-cli mini-css-extract-plugin --save-dev
    # 或
    npm install terser clean-css --save
  2. 运行脚本

    # Gulp
    npx gulp

Webpack

npx webpack

自定义脚本

node merge-assets.js


选择哪种方式取决于你的项目需求和团队技术栈:
- **Gulp**:简单直观,适合传统项目
- **Webpack**:功能强大,适合现代前端项目
- **自定义脚本**:灵活性最高,适合特殊需求

抱歉,评论功能暂时关闭!