究竟什么是前端脚手架? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
461229187
V2EX    前端开发

究竟什么是前端脚手架?

  •  
  •   461229187
    codexu 2019-06-14 17:06:13 +08:00 4665 次点击
    这是一个创建于 2387 天前的主题,其中的信息可能已经有所发展或是发生改变。

    咱也不知道咱也不敢问啊

    先查查百度百科里对“脚手架”的定义吧:

    脚手架是为了保证各施工过程顺利进行而搭设的工作平台。

    然后搜一下“脚手架”,基本上都是以下几类:

    • Vue/React 脚手架

    • 使用 Node、yeoman 打造自己的脚手架

    • 从零搭建 webpack 脚手架

    此时还是无法确定什么是“脚手架”,也许我心目中的脚手架应该是 vue/cli 或者 create-react-app 吧,然后我打开他们的文档,但是他们的介绍上并没有说这是一款脚手架...

    谈一下我自己的“脚手架”

    我最怕别人看到我的“脚手架”后说这有什么卵用...

    看了一下我第一次在 Github 上的提交记录 Commits on Feb 13, 2017,我入行三年多,那时应该是我第一次进入前端工程化的时候吧。在此之前我在公司接手的都是一些很简单的项目,直接新建文件夹,随手下载一个 jQuery,然后新建 index.html main.js style.css ,有没有同样经历的小伙伴们?

    后来做的项目多了,觉得每次这么新建项目太麻烦,我新建了一个文件夹,专门存放初始的模板,然后复制粘贴,继续撸。

    再后来,接触到 vue,他可以实现在终端内输入一行指令就能生成模板,这可比我复制粘贴看起来高端多了,为了装逼我开始了研究如何开发自己的“脚手架”。

    当时还真是没有几篇文章把这种操作说的很明白,甚至我并不知道我要做的东西叫什么(脚手架)。

    我理解的“脚手架”

    百科里说的很对我的思路,首要的就是保证我的项目可以顺利进行。

    • 能够快速帮我生成新项目的目录模板(Node.js)。

    • 能够提升我的开发效率和开发的舒适性(webpack)。

    分享点干货

    从零搭建这种我就不说了,毕竟一搜一堆,基本上就是推荐几个库,例如 commander、inquirer、ora 等等。分享一些在我的脚手架开发时遇到的一些问题和需求,分享想给大家。

    版本验证

    首先推荐工具库:

    semver,版本对比。

    request,发送请求,当然你也可以用 axios。

    const semver = require('semver'); const request = require('request'); 
    • Node.js 版本验证

    如果你的脚手架想分享给别人用,这步最好不要避免,因为如果你用了一些现代化的 ES 语法,比如说 async await,老版本跑不起来的。

    function checkNodeVersion (wanted) { // process.version 可以获取当前的 node 版本 if (!semver.satisfies(process.version, wanted)) { console.log('Node 版本不支持巴拉巴拉'); // 退出进程 process.exit(1); } } 
    • 脚手架版本验证

    正如上面所说,你如果分享给别人用,在你修改了一些 bug 后,希望其他人用最新的版本,那就应该提示他。

    function checkPackageVersion(url) { return new Promise((resolve, reject) => { request(url, function (error, response, body) { if (!error && response.statusCode === 200){ let version = JSON.parse(body).version; if (semver.lte(version, requiredVersion)) { resolve(); } else { console.log('需要更新你的包巴拉巴拉'); process.exit(1); } } else { console.log('发送请求失败巴拉巴拉'); resolve(); } }); }); } 

    参数 url 当然传入 npm 的链接 https://registry.npmjs.org/[你的包名]/latest

    当前路径下是否存在相同的文件夹

    如果不做这层判断,你新生成的项目很可能会覆盖你已有的项目,别问我为啥想到这么做

    function hasFolder(name) { return new Promise (resolve => { fs.exists(name, exists => { if (exists) { console.log('已经存在相同目录巴拉巴拉'); process.exit(1); } else { resolve(); } }); }); }; 

    这里加了一层 Promise 是因为 Node 去检测是否存在文件夹是个异步操作,也需要耗时,这么做比较保险。

    清空控制台

    当你输入完命令后,好像进入了新的页面一样,看起来很舒服。

    function clearConsole(color, str) { if (process.stdout.isTTY && store.cmd !== 'test') { const blank = '\n'.repeat(process.stdout.rows); console.log(blank); readline.cursorTo(process.stdout, 0, 0); readline.clearScreenDown(process.stdout); } } 

    拷贝模板

    很多关于如果构建脚手架里提到一个工具 download-git-repo,在 github 或其他仓库中下载模板。我并不是很喜欢这种操作,1、耗时,让脚手架构建速度更慢了,在没有网络的情况下无法构建。2、在 git 仓库中还需要新建项目模板,感觉把一个项目分离成了两个,不方便管理。

    所以我打算直接从全局目录下将模板文件夹拷贝到当前路径下:

    使用一个工具 fs-extra,node.js 新手最好不要试图用原生接口拷贝一个文件夹。

    const src = path.resolve(__dirname, '../template');

    const dest = path.resolve(process.cwd(), store.dirname);

    两个概念:

    全局环境路径:

    const src = path.resolve(__dirname, '你的模板文件夹相对路径') 

    当前环境路径:

    const dest = path.resolve(process.cwd(), '你创建项目的名称'); 
     fs.copy(src, dest).then(() => /* 巴拉巴拉 */); 

    自动选择包管理器

    现在用 yarn 的人越来越多,而且确实效率很高,如果安装过 yarn 就让它作为默认包管理器去自动安装依赖吧。

    function packageManagement() { try { child_process.execSync('yarnpkg --version', { stdio: 'ignore' }); return 'yarn'; } catch (e) { return 'npm'; } } 

    自动安装依赖

    这里用到 Node.js 中的 child_process.spawn 方法

    这里举个例子,想要执行 npm install webpack -D

    const ls = spawn('npm', ['isntall', 'webpack', '-D'], {shell: true}); ls.on('close', (code) => /* 巴拉巴拉 */) 
    • 第一个参数:要运行的命令。

    • 第二个参数:数组,字符串参数的列表。

    • 第三个参数:配置,这里把 shell 设置为 true。

    • 使用 on 方法监听执行结果。

    这里推荐安装的包带有版本号,如果直接安装会安装最新版,可能会导致不兼容。

    提一个 webpack 的插件

    ProgressPlugin,用于监听编译进度。

    plugins: [ new webpack.ProgressPlugin(function(percentage) { // percentage 进度 0-1 }) ] 

    这里配合前面说到的清空控制台,可以实现更好的体验。

    使用 IP 访问项目

    这里指的是通过 webpack 启动的 devServer。

    host 配置为 0.0.0.0

    通过下面的函数获取到本机的 IP 地址,这样就可以在同网下使用移动设备做测试了。

    function getIPAdress() { let interfaces = require('os').networkInterfaces(); // eslint-disable-next-line guard-for-in for (let devName in interfaces) { let iface = interfaces[devName]; for (let i = 0; i < iface.length; i++) { let alias = iface[i]; if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) { return alias.address; } } } } 

    再逼逼几句

    这是我理解中的“脚手架”,希望其他小伙伴也评论一下自己理解的脚手架。

    已经近一年没有做过技术分享了,每天在掘金里潜水,偶尔发点沸点,不敢在首页发内容,总觉得自己技术不足,怕大佬喷,自尊心受到创伤。

    最后分享一下我的“脚手架”,这个项目在我面试中也起到了不错的效果:

    文档: https://codexu.github.io/

    7 条回复    2019-06-20 15:42:04 +08:00
    Tink
        1
    Tink  
    PRO
       2019-06-14 18:53:33 +08:00 via iPhone
    同问
    img src="https://cdn.v2ex.com/avatar/4571/ffbc/265735_normal.png?m=1721278543" class="avatar" border="0" align="default" alt="wu67" data-uid="265735" />
        2
    wu67  
       2019-06-14 19:20:07 +08:00
    其实就我用过的 vue 来说, 只要会看文档改配置就行了, 从 0 开始过于蛋疼, 也看不进去...
    billlee
        3
    billlee  
       2019-06-14 20:02:00 +08:00   1
    不是前端,但我觉得各种手脚架就是各种框架、开发工具不够完善的产物。框架和开发工具步完善导致每个项目都要写很多重复的代码或配置,这些就被做成了手脚架。
    xrr2016
        4
    xrr2016  
       2019-06-14 20:22:16 +08:00 via Android   1
    666 赞一个
    aleung
        5
    aleung  
       2019-06-14 20:58:50 +08:00 via Android
    基于 mrm 开发自己的 preset,比较好的做脚手架的基础工具。https://github.com/sapegin/mrm
    lxml
        6
    lxml  
       2019-06-14 22:50:05 +08:00
    @billlee #3 是这样的,js 太烂,比如光 lint 就一堆标准,太多标准的根本原因就是因为毫无标准
    kalasoo
        7
    kalasoo  
       2019-06-20 15:42:04 +08:00
    掘友爱你
    来自掘金的爱
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana   span class="snow">   1339 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 22ms UTC 16:57 PVG 00:57 LAX 08:57 JFK 11:57
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86