可能很多同学还不知道 Farm , 先给大家介绍一下, Farm 是一个基于 Rust 的 Web 构建工具, 类似 webpack 和 vite,但更快。 Farm 用 resolve, load, transform 把所有的 asset (js/jsx/ts/tsx、css/sass/less、html、静态资源、json 等),并将它们打包成一系列可部署文件。 Farm 作为一个速度极快的构建工具,可帮助您更快的构建出 web / nodejs 应用程序。
接下来就进入正题, 那么如何从已有的 vite 项目迁移到 Farm 呢 ?
从 vite 迁移到 farm 其实非常简单, 因为 farm 内置了对 vite 插件的兼容, 所以您只需要做的是将 vite.config.ts 转换成 farm.config.js。
但是需要注意的是
我们先从基础项目来体会一下从 vite 迁移到 Farm 有多简单
首先还是我们熟悉的创建 vite 项目
pnpm create vite
我们选一个 Vue 项目模版, 创建好项目之后, 我们的 vite.config.ts 应该是这样的
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
})
那么把大象放进冰箱一共需要三步
pnpm install @farmfe/core @farmfe/cli -D
import { defineConfig } from '@farmfe/core'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
vitePlugins: [vue()],
})
然后我们在控制台执行 npx farm start 控制台就可以看到以下命令
执行构建命令 npx farm build
这样就大功告成啦, 是不是非常简单。
接下来我们来迁移一个比较复杂的项目, vue-pure-admin 是一个全面ESM+Vue3+Vite+Element-Plus+TypeScript 编写的一款后台管理系统, 并且模块数量算是比较大, 那么我们使用 Farm 来迁移这个项目, 来进一步体现出 Farm 的优势. 以及迁移的成本到底有多低
首先我们先克隆一下 pure-admin 的仓库代码, 然后查看一下项目的 vite 配置文件, 并提示出迁移所需要修改的地方
import { getPluginsList } from "./build/plugins";
import { include, exclude } from "./build/optimize";
import { type UserConfigExport, type ConfigEnv, loadEnv } from "vite";
import {
root,
alias,
warpperEnv,
pathResolve,
__APP_INFO__
} from "./build/utils";
export default ({ mode }: ConfigEnv): UserConfigExport=> {
const { VITE_CDN, VITE_PORT, VITE_COMPRESSION, VITE_PUBLIC_PATH }=warpperEnv(loadEnv(mode, root));
return {
base: VITE_PUBLIC_PATH,
root,
resolve: {
alias
},
// 服务端渲染
server: {
// 端口号
port: VITE_PORT,
host: "0.0.0.0",
// 预热文件以提前转换和缓存结果,降低启动期间的初始页面加载时长并防止转换瀑布
warmup: {
clientFiles: ["./index.html", "./src/{views,components}/*"]
}
},
plugins: getPluginsList(VITE_CDN, VITE_COMPRESSION),
// https://cn.vitejs.dev/config/dep-optimization-options.html#dep-optimization-options
optimizeDeps: {
include,
exclude
},
build: {
// https://cn.vitejs.dev/guide/build.html#browser-compatibility
target: "es2015",
sourcemap: false,
// 消除打包大小超过500kb警告
chunkSizeWarningLimit: 4000,
rollupOptions: {
input: {
index: pathResolve("./index.html", import.meta.url)
},
// 静态资源分类打包
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]"
}
}
},
define: {
__INTLIFY_PROD_DEVTOOLS__: false,
__APP_INFO__: JSON.stringify(__APP_INFO__)
}
};
};
farm 配置基本平替 vite 配置, 我们再来看一下迁移到 farm 所需要修改的配置文件,由于对 css 的处理 farm 和 vite 的处理方向上的差异,所以我们只需要把一些 css 的插件配置替换成 farm 的插件, 其他的 vite 插件完全可以复用
import { getPluginsList } from "./build/plugins";
import { type UserConfigExport, type ConfigEnv, loadEnv } from "@farmfe/core";
import { root, alias, warpperEnv, __APP_INFO__ } from "./build/utils";
import postcss from "@farmfe/js-plugin-postcss";
import sass from "@farmfe/js-plugin-sass";
export default ({ mode }: ConfigEnv): UserConfigExport=> {
const { VITE_CDN, VITE_PORT, VITE_COMPRESSION, VITE_PUBLIC_PATH }=warpperEnv(loadEnv(mode, root)[0]);
return {
compilation: {
output: {
publicPath: VITE_PUBLIC_PATH,
targetEnv: "browser-es2015",
filename: "static/[ext]/[name]-[hash].[ext]",
assetsFilename: "static/[ext]/[name]-[hash].[ext]"
},
resolve: {
alias
},
script: {
plugins: [
{
name: "@swc/plugin-remove-console",
options: {
exclude: ["error"]
},
filters: {
moduleTypes: ["js", "ts", "jsx", "tsx"]
}
}
]
},
externalNodeBuiltins: false,
define: {
__INTLIFY_PROD_DEVTOOLS__: false,
__APP_INFO__: process.env.FARM_FE
? __APP_INFO__
: JSON.stringify(__APP_INFO__)
}
},
root,
// 服务端渲染
server: {
// open: true,
port: VITE_PORT
},
plugins: [
sass({
legacy: true
}),
postcss(),
{
name: "remove-css-filter-plugin",
priority: 0,
transform: {
filters: {
resolvedPaths: ["element-plus/dist/index.css"]
},
async executor({ content }) {
return {
content: content.replace(/filter:\s*alpha\(opacity=0\);/g, "")
};
}
}
}
],
vitePlugins: getPluginsList(VITE_CDN, VITE_COMPRESSION)
};
};
我们可以看到 vite 插件完全复用, 需要修改的地方仅仅是一些编译输出的属性, 整体最大的修改点只有这些,我在 vue-pure-admin 项目提了一个 pr, 还有一些设计差异的小细节大家可以在这里 查看 尽管从 Vite 迁移到 Farm 需要进行一些调整和适配,但是这个过程并不复杂,而且可以通过优化提升项目的性能和开发效率。因为确实迁移很简单, 所以本篇文章只是简单的介绍一下 Farm 目前的可用度,随着 Farm 的不断发展和完善,相信它会成为更多项目的首选构建工具。
注:因为 vite 对于源代码是请求时编译,所以此处加上了 “项目可访问时间”(即 “热启动时间” + “页面加载时间”),作为另一个指标来综合对比性能。所以 Farm 在热启动比 vite 快 5 倍左右
farm 已经具有了 所有开发调试 发布 也有很大的提升空间
Farm 开源已经一年多了, 也已经正式的发布了 1.0 版本, 已经达到了生产可用的状态, 不仅仅是从 vite 中迁移, 在 webpack 中迁移, 团队中也做了非常多的尝试, 迁移成本都很低, Farm 下一步计划基于 Farm 打造出下一代 SSR 框架, 也希望可以有更多的同学参与进来, 共同学习进步。
未来,我们将继续撰写更多的文章,深入介绍 Farm 的各项功能以及特性和原理解析,帮助大家更好地理解和使用下一代的构建工具,可以对前端工程化以及代码解析与编译的原理理解之后, 可以更加深入地了解现代前端开发的核心概念和技术,并掌握构建高效、稳定的前端项目的关键技能。让我们共同期待未来的探索和发现,共同探讨前端技术的前沿话题,为构建更加美好的 Web 世界贡献一份力量。
链接:https://juejin.cn/post/7352837711339814963
迎搜索公众号:白帽子左一
每天分享更多黑客技能,工具及体系化视频教程(免费领)
来源:HACK学习呀
一直找不到目标站点,昨天下午收到的一条微信之后突然有了目标
还是老规则 下载了APP 这里提示下注意事项
因为这种APP是自动采用微信账号登录 且苹果手机登录前需要申请数据网络权限
所以在进行抓包前 ,需要先点开APP给予数据网络权限并提前登录微信账号(设置代理之后无法登录微信
进入APP后、 首先对APP内部通过http请求获取或得到数据的接口进行了测试, 也测试得到APP走http请求的IP为 ,阿里云服务器IP地址
注意事项 碰到阿里云服务器(不要进行端口扫描,不要进行网页路径探测)
因为这两点都会让阿里云封你的IP 首先对反馈接口进行了抓包 丢入了XSS
丢入xss 之后 考虑到这个APP并没有什么可以入手的点
(本人比较菜,没办法在这上面找到突破口)
于是注意到这个APP有挂载的官网,果断从官网开始入手
首先找到了部分代理登录的后台,进入了登录界面,因为有两个登录界面 一个是http 并且无验证码
一个是https 有验证码 首先从http无验证码口开始爆破密码
https://jingyan.baidu.com/article/200957619c8739cb0721b4ff.html
Burp爆破网站后台账号密码步骤
成功的登录了后台,发现后台并没有什么其他功能 只是能查看个人的代理及充值返利情况
在未找到直接能getshell的点, 首先对网站后台进行了抓包, 查看后台中部分搜索功能是否存在SQL注入,其次查看后台是否存在逻辑漏
可以确定的点如下(网站后台未存在有SQL注入,数据库不进行报错,对网站进行扫描并未封IP
IP地址为武汉,极有可能是源IP地址,接着继续寻找网站的逻辑漏洞
当咱们对myuser.php 进行访问时 服务器缓存的cookie 信息为以上图片内
aliyungf_tc 为无效数据 可无视不计算
user_name 为账号信息 user_id为服务器uid值 user_level为用户等级
尝试修改账号信息为123456789 数据并未发生改变
尝试修改uid值 数据发生改变
尝试修改用户等级 未发生改变
于是得到uid 值为判断用户的标准
接下来 就找我亲爱的丁哥写了套爬虫 (用户uid值为循环上升,爬取页面内容 得到网站总用户量为1万五千人)
之前咱们提到还有一个https的后台
有验证码机制
有验证码机制进行爆破成功率可能并不是很高 尝试进行找回密码功能
修改uid值为空试试
点击确认提交 直接来到了修改密码的页面
https://qy.xxxxxxx.com/user_goback_password.php?uid=
再进行uid补全为test用户uid=11000 输入更改的新密码 更改成功
成功进入后台 截止到目前为止
(拿到了网站全部用户的个人信息,拿到了充值游戏币的权限)
顺便解释下为什么能更改成功test用户的密码
当user_goback_quan.php?uid=11000 修改为uid=空时
数据库查询不到用户 那么对应的答案也是查询不到 为空的
更改密码在数据库判断中 问题=答案(正确) ----- 更改成功
当问题不存在 答案不存在的情况下 问题=答案 跳转到更改密码界面 — 更改uid值为test用户uid=====成功更改test用户密码
// 在已经创建好的项目中安装插件
vue add element
// 安装过程中的选项
? Successfully installed plugin: vue-cli-plugin-element
? How do you want to import Element? Fully import
? Do you wish to overwrite Element's SCSS variables? No
? Choose the locale you want to load zh-CN
npm run serve
// 运行结果
DONE Compiled successfully in 6537ms 22:40:55
App running at:
- Local: http://localhost:8080/
- Network: http://192.168.1.9:8080/
vue add router
? Installing @vue/cli-plugin-router...
+ @vue/cli-plugin-router@4.4.4
updated 1 package in 16.079s
42 packages are looking for funding
run `npm fund` for details
? Successfully installed plugin: @vue/cli-plugin-router
? Use history mode for router? (Requires proper server setup for index
fallback in production) No `N`
// 1.根据element Container 布局容器创建主界面
<template>
</template>
<script>
export default {
}
</script>
<style>
</style>
// 2.修改router下index.js
import Main from '../views/Main.vue'
{
path: '/',
name: 'main',
component: Main
}
// 3.简化App.vue 只保留router-view
<div id="app">
<router-view/>
</div>
// 4.去除App.vue 中样式,初始化样式表 margin: 0;padding: 0;
// 5.修改Main.vue 中高度样式表style="height: 100vh;"
//保留基本结构
<template>
<el-container style="height: 100vh;">
<el-aside width="200px" style="background-color: rgb(238, 241, 246)">
<el-menu :default-openeds="['1', '3']">
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>导航一</template>
<el-menu-item index="1-1">选项1</el-menu-item>
<el-menu-item index="1-2">选项2</el-menu-item>
<el-menu-item index="1-3">选项3</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<el-container>
<el-header style="text-align: right; font-size: 12px">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px"></i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>查看</el-dropdown-item>
<el-dropdown-item>新增</el-dropdown-item>
<el-dropdown-item>删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<span>王小虎</span>
</el-header>
<el-main>
<el-table :data="tableData">
<el-table-column prop="date" label="日期" width="140">
</el-table-column>
<el-table-column prop="name" label="姓名" width="120">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
</el-table>
</el-main>
</el-container>
</el-container>
</template>
<style>
.el-header {
background-color: #B3C0D1;
color: #333;
line-height: 60px;
}
.el-aside {
color: #333;
}
</style>
<script>
export default {
data() {
const item={
date: '2020-08-08',
name: '墨客moke',
address: '青海省西宁市'
};
return {
tableData: Array(20).fill(item)
}
}
};
</script>
// 管理后台客户端分类列表创建
// Main.vue
// 1:新建分类、分类列表
// 2:添加 router 属性
// 3:导航菜单添加路由
<el-menu router :default-openeds="['1']"> <!-- 导航菜单收缩 --> <!-- router属性 -->
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>内容管理</template>
<el-menu-item-group>
<template slot="title">分类</template>
<el-menu-item index="/categories/create">新建分类</el-menu-item>
<el-menu-item index="/categories/list">分类列表</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
为Main.vue
新建CategoriesEdit子组件
// 1.CategoriesEdit.vue
// 2.添加Main子路由
// 3.请求远程数据接口
// 安装插件
F:\client\node-vue-moba\admin>cnpm i axios
√ Installed 1 packages
√ Linked 3 latest versions
√ Run 0 scripts
√ All packages installed (4 packages installed from npm registry, used
593ms(network 587ms), speed 26.3kB/s, json 4(15.44kB), tarball 0B)
// 配置使用
// http.js
import axios from 'axios'
const http=axios.create({
baseURL : 'http://localhost:3000/admin/api'
})
export default http
// main.js 创建axios实例
import http from './http'
Vue.prototype.$http=http
查看相关内容见 0x04CRUD接口开发
<template>
<div class="about">
<h1>{{id ? '编辑' : '新建'}}分类</h1>
<el-form label-width="120px" @submit.native.prevent="save">
<el-form-item label="名称">
<el-input v-model="model.name"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" native-type="submit">保存</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
props:{
id:{}
},
data(){
return {
model:{}
}
},
methods:{
async save(){
// 列表新建和编辑数据更新
if (this.id) {
await this.$http.put(`categories/${this.id}`,this.model)
} else {
await this.$http.post('categories',this.model)
}
// 跳转至分类列表
this.$router.push('/categories/list')
this.$message({
type: 'sucess',
message: '保存成功'
})
},
// 分类编辑1:获取分类数据
// 分类编辑2:修改后更新数据
async fetch(){
const res=await this.$http.get(`categories/${this.id}`)
this.model=res.data
}
},
created(){
this.id && this.fetch()
}
}
</script>
<style>
</style>
<template>
<div class="about">
<h1>分类列表</h1>
<el-table :data="items">
<el-table-column prop="_id" label="ID" width="245"></el-table-column>
<el-table-column prop="name" label="分类名称"></el-table-column>
<el-table-column fixed="right" label="操作" width="180">
<template slot-scope="scope">
<el-button type="text" size="small" @click="$router.push(`/categories/edit/${scope.row._id}`)">编辑</el-button>
<el-button type="text" size="small" @click="remove(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data(){
return {
items:[]
}
},
methods:{
async fetch(){
const res=await this.$http.get('categories')
this.items=res.data
},
async remove(row){
this.$confirm(`是否确定删除${row.name}?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async ()=> {
await this.$http.delete(`categories/${row._id}`),
this.$message({
type: 'success',
message: '删除成功!'
});
this.fetch()
})
}
},
created(){
this.fetch()
}
}
</script>
<style>
</style>
感谢阅读,欢迎交流。
*请认真填写需求信息,我们会在24小时内与您取得联系。