本文目录导读:

我来介绍几种实现静态资源合并脚本的方法,包括前端构建工具方案和纯脚本方案。
使用 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);
}
}
}
使用方法
-
安装依赖:
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
-
运行脚本:
# Gulp npx gulp
Webpack
npx webpack
自定义脚本
node merge-assets.js
选择哪种方式取决于你的项目需求和团队技术栈:
- **Gulp**:简单直观,适合传统项目
- **Webpack**:功能强大,适合现代前端项目
- **自定义脚本**:灵活性最高,适合特殊需求