上传文件至 /

This commit is contained in:
zenghuanyu 2024-04-02 17:38:33 +08:00
commit 9d32fc9a9b
5 changed files with 16244 additions and 0 deletions

37
README.md Normal file
View File

@ -0,0 +1,37 @@
## 简介
采用 Gulp 4.0.2 搭建的 js 自动构建任务项目
## 安装使用
请先安装**Node 14 和 Npm**,安装过程略过。
- 安装依赖
```bash
npm i
```
- 运行
```bash
npm run dev
```
- 打包
```bash
npm run build
```
## 目录介绍
- dist打包结果目录
- src源码目录
- src/modules公共 html 目录,此目录的 html 不会出现在打包结果中,此目录的 html 中引入 css 或者 js请使用绝对路径如/js/xxx.js /css/xxx.css其他资源如图片也是如此
- src/csscss 源码
- src/jsjs 源码
- src/static静态文件如第三方库第三方样式等可以放在此处打包时不会进入文件转换流程会直接复制到打包结果中
- src/index.html网站入口
- config.js打包配置
- gulpfile.jsgulp 构建流程

31
config.js Normal file
View File

@ -0,0 +1,31 @@
export default {
// 用于代码替换key为文件idvalue内容所在文件路径为绝对路径/为根目录
// 在html中使用#include函数引入如#include(navbar)
moduleMap: {
'navbar': '/src/modules/navbar.html',
"footer": '/src/modules/footer.html',
},
assetsDir: "dist",
devServer: {
// 详情配置请看 https://www.npmjs.com/package/http-proxy-middleware#options
httpProxy: {
// "/api": {
// target: '', // 替换为你的后端服务器地址
// changeOrigin: true, // 如果需要的话改变请求的origin
// pathRewrite: {
// '^/api': '' // 移除请求中的/api前缀
// },
// logLevel: "debug"
// }
},
// 详情配置请看 https://browsersync.io/docs/options#option-server middleware和server不可配置
browsersync: {
host: 'localhost',
port: 3000,
open: true,
ui: {
port: 3001
}
}
}
}

273
gulpfile.js Normal file
View File

@ -0,0 +1,273 @@
import gulp from "gulp";
import gulpIf from "gulp-if";
import MemoryFS from "memory-fs";
import syncBrowser from "browser-sync";
const browserSync = syncBrowser.create();
const __dirname = process.cwd();
// 创建内存文件系统实例
const mfs = new MemoryFS();
import htmlmin from "gulp-htmlmin"; // 压缩html文件
import uglify from "gulp-uglify"; // 压缩js文件
import babel from "gulp-babel"; // ES6转ES5
import sass from "gulp-sass"; // sass编译
import cleanCss from "gulp-clean-css"; // 压缩css文件
import replace from "gulp-replace"; // 替换文件内容
import ignore from "gulp-ignore"; // 排除文件不进入打包结果
import { deleteAsync } from "del"; // 清除打包目标目录
import fs from "fs/promises";
import path from "path";
import map from "map-stream";
import { createProxyMiddleware } from "http-proxy-middleware";
const devAssetsDir = "src";
const htmlGlob = `${devAssetsDir}/**/*.html`;
const cssGlob = `${devAssetsDir}/**/*.css`;
const jsGlob = `${devAssetsDir}/**/*.js`;
const staticGlob = `${devAssetsDir}/static/**/*`;
const modulesGlob = "modules/**/*";
const allFileGlob = `${devAssetsDir}/**/*`;
/**
* @type {"dev" | "prod"} 环境变量
*/
let env = "dev";
function setEnv(currEnv) {
return async () => {
env = currEnv;
};
}
import config from "./config.js";
let { moduleMap, assetsDir, devServer } = config;
let { browsersync: browsersyncOptions, httpProxy } = devServer && typeof devServer === "object" ? devServer : {};
moduleMap = parseModuleMap(moduleMap);
// 异步读取文件内容
async function getCode(path) {
return await fs.readFile(path, "utf8");
}
// 清除dist目录的任务
async function cleanTask() {
return deleteAsync([assetsDir]); // 使用 del 删除 dist 目录及其内容
}
export const clean = cleanTask;
/**
* @description 注入模块
* @param {NodeJS.ReadWriteStream} ctx
* @returns {NodeJS.ReadWriteStream}
*/
async function injectModules(ctx) {
// 遍历模块文件,将每个模块文件的内容替换到对应的模块标签中
for (const key in moduleMap) {
const filePath = path.join(__dirname, moduleMap[key]);
const code = await getCode(filePath);
const replaceStream = replace(key, code);
ctx = ctx.pipe(replaceStream);
}
return ctx;
}
// 制定html任务
async function htmlTask() {
const condition = env === "prod";
let ctx = gulp.src(htmlGlob, {
ignore: [staticGlob],
});
ctx = await injectModules(ctx);
return (
ctx
.pipe(
htmlmin({
removeComments: condition, // 生产环境下移除注释
collapseWhitespace: condition, // //压缩HTML
collapseBooleanAttributes: condition, //省略布尔属性的值 <input checked="true"/> ==> <input />
removeEmptyAttributes: env === "prod", //删除所有空格作属性值 <input id="" /> ==> <input />
removeScriptTypeAttributes: false, //删除<script>的type="text/javascript"
removeStyleLinkTypeAttributes: condition, //删除<style>和<link>的type="text/css"
minifyJS: condition, //压缩页面JS
minifyCSS: condition, //压缩页面CSS
})
)
.pipe(ignore.exclude(modulesGlob)) // 忽略模块文件
.pipe(gulpIf(condition, writeFileToFileSystem(assetsDir)))
// 将处理后的文件写入内存文件系统
.pipe(gulpIf(!condition, writeFileToMemory()))
);
}
// 定义Gulp任务
export const html = htmlTask;
// 制定js任务ES6转ES5再压缩js
async function jsTask() {
const ctx = gulp.src(jsGlob, {
ignore: [staticGlob],
});
const condition = env === "prod";
return ctx
.pipe(
gulpIf(
condition,
babel({
presets: ["@babel/preset-env"],
})
)
)
.pipe(
gulpIf(
condition,
uglify({
compress: {
drop_console: false, // 移除console语句
drop_debugger: true, // 移除debugger语句
},
})
)
)
.pipe(gulpIf(condition, writeFileToFileSystem(path.join(assetsDir))))
.pipe(gulpIf(!condition, writeFileToMemory()));
}
export const js = jsTask;
// css任务压缩css
async function cssTask() {
const ctx = gulp.src(cssGlob, {
ignore: [staticGlob],
});
const condition = env === "prod";
return ctx
.pipe(gulpIf(condition, cleanCss())) // css样式压缩
.pipe(gulpIf(condition, writeFileToFileSystem(path.join(assetsDir))))
.pipe(gulpIf(!condition, writeFileToMemory()));
}
export const css = cssTask;
// 静态文件目录,直接复制
async function staticFile() {
const condition = env === "prod";
const staticDir = "/static";
return gulp
.src(staticGlob)
.pipe(gulpIf(condition, writeFileToFileSystem(assetsDir)))
.pipe(gulpIf(!condition, writeFileToMemory(staticDir)));
}
export const staticFileTask = staticFile;
// 其他文件直接复制除了html, cssjs文件和static目录
async function otherFile() {
const condition = env === "prod";
return gulp
.src(allFileGlob, {
ignore: [htmlGlob, cssGlob, jsGlob, staticGlob],
})
.pipe(gulpIf(condition, writeFileToFileSystem(assetsDir)))
.pipe(gulpIf(!condition, writeFileToMemory()));
}
export const otherFileTask = otherFile;
// 打包任务清除dist目录然后并行执行html、js、css、其他文件、static等任务
export const build = gulp.series(setEnv("prod"), cleanTask, gulp.parallel(html, js, css, otherFileTask, staticFileTask));
// server任务开启一个本地服务器
async function serverTask() {
browsersyncOptions = browsersyncOptions && typeof browsersyncOptions === "object" ? browsersyncOptions : {};
const httpProxyList = Object.keys(httpProxy).map((prefix) => createProxyMiddleware(prefix, httpProxy[prefix]));
return browserSync.init({
...browsersyncOptions,
middleware: [
...httpProxyList,
// 自定义中间件来从内存文件系统中提供文件
function (req, res, next) {
let fileLogicPath = req.url.split("?")[0];
let url = fileLogicPath === "/" ? "/index.html" : fileLogicPath;
let filePath = path.join(__dirname, "/", devAssetsDir, ...url.split("/"));
mfs.readFile(decodeURIComponent(filePath), (err, data) => {
if (err) {
const map = {
ENOENT: () => console.error(`\x1b[31m找不到文件或目录${err.path}\x1b[0m`),
};
map[err.code] ? map[err.code]() : console.error(err);
res.statusCode = 404;
res.end(`not found ${req.url}`);
} else {
res.end(data);
}
});
},
],
server: true,
});
}
export const server = serverTask;
// 监听文件的修改,执行对应的任务
async function watchTask() {
gulp.watch(htmlGlob, gulp.series(html)).on("change", browserSync.reload);
gulp.watch(jsGlob, gulp.series(js)).on("change", browserSync.reload);
gulp.watch(cssGlob, gulp.series(css)).on("change", browserSync.reload);
gulp.watch(staticGlob, gulp.series(staticFileTask)).on("change", browserSync.reload);
gulp.watch(allFileGlob, gulp.series(otherFileTask)).on("change", browserSync.reload);
}
export const watch = watchTask;
// 开发服务
export const dev = gulp.series(setEnv("dev"), gulp.parallel(html, js, css, staticFileTask, otherFileTask), (cb) => setTimeout(() => cb(), 3000), server, watch);
/**
* 解析模块映射
* @param {Object} moduleMap
* @returns
*/
function parseModuleMap(moduleMap) {
const newModuleMap = {};
Object.keys(moduleMap).forEach((fileId) => {
const newId = `#include(${fileId})`;
newModuleMap[newId] = moduleMap[fileId];
});
return newModuleMap;
}
/**
* @description 把文件流写入到内存中
* @returns
*/
function writeFileToMemory() {
return map(function mapFile(file, cb) {
const filepath = path.resolve(file.path);
const dir = path.dirname(filepath);
if (!mfs.existsSync(dir)) {
mfs.mkdirpSync(dir);
}
file.contents && mfs.writeFileSync(filepath, file.contents);
cb(null, file);
});
}
/**
* @description 把文件流写入到硬盘中
* @param {String} assetsDir 写入到哪个目录如根目录的dist,则assetsDir位'dist'
* @returns
*/
function writeFileToFileSystem(assetsDir) {
return map(async function mapFile(file, cb) {
const relativePath = path.relative(path.join(process.cwd(), devAssetsDir), file.path);
const destFilePath = path.join(process.cwd(), assetsDir, relativePath);
const dirPath = path.dirname(destFilePath);
try {
if (file.contents) {
await fs.access(dirPath).catch(() => fs.mkdir(dirPath, { recursive: true }));
await fs.writeFile(destFilePath, file.contents);
}
} catch (error) {
console.log(error);
}
cb(null, file);
});
}

15870
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

33
package.json Normal file
View File

@ -0,0 +1,33 @@
{
"name": "gulp",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "gulp dev",
"build": "gulp build"
},
"type": "module",
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.24.0",
"@babel/preset-env": "^7.24.0",
"browser-sync": "^3.0.2",
"del": "^7.1.0",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
"gulp-clean-css": "^4.3.0",
"gulp-debug": "^5.0.1",
"gulp-htmlmin": "^5.0.1",
"gulp-if": "^3.0.0",
"gulp-ignore": "^3.0.0",
"gulp-replace": "^1.1.4",
"gulp-sass": "^5.1.0",
"gulp-uglify": "^3.0.2",
"http-proxy-middleware": "^2.0.6",
"map-stream": "^0.0.7",
"memory-fs": "^0.5.0"
}
}