上传文件至 /
This commit is contained in:
commit
9d32fc9a9b
|
@ -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/css:css 源码
|
||||
- src/js:js 源码
|
||||
- src/static:静态文件,如第三方库,第三方样式等可以放在此处,打包时不会进入文件转换流程,会直接复制到打包结果中
|
||||
- src/index.html:网站入口
|
||||
- config.js:打包配置
|
||||
- gulpfile.js:gulp 构建流程
|
|
@ -0,0 +1,31 @@
|
|||
export default {
|
||||
// 用于代码替换,key为文件id,value内容所在文件路径,为绝对路径,/为根目录
|
||||
// 在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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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, css,js文件和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);
|
||||
});
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user