从零开始的<vue2项目脚手架>搭建:vite+vue2+eslint

前言

为了写 demo 或者研究某些问题,我经常需要新建空项目。每次搭建项目都要从头配置,很麻烦。所以我决定自己搭建一个项目初始化的脚手架(取名为 lily-cli)。

脚手架(scaffolding):创建项目时,自动完成的创建初始文件等初始化工作。这些工作往往是每次新建工程都要进行的重复性工作。

目标:我只需要执行 npm init lily-cli,就会自动创建一个符合我要求(vite+vue2+eslint)的空项目。

碎碎念:
现在 vue3 是主主主主流。我作为一个不得不使用 vue2 的开发者,在 vue3 浪潮下想要搜索 vue2 的内容真的有一点点麻烦——比如说,vite 已经不提供 vue2 的官方初始化模板了,而 vite 的社区模板也没有适合我的,所以我还是自己搭建一个吧。

分成两步实现:

  1. 手动创建一个 vite+vue2+eslint 的项目
  2. 以上一步的项目作为模板,写一个脚本自动创建新项目

Step 1:手动创建项目 vite+vue2+eslint

初始化

新建文件夹 template_vite_vue2_eslint
npm init -y

vite + vue2

在 vite 中使用 vue2.7+,要用 @vitejs/plugin-vue2。这个插件已经不再更新了,安装时可以直接锁定最新版本 2.3.1。

vite 和 vue 的版本要看 @vitejs/plugin-vue2 的要求:

// @vitejs/plugin-vue2 最新版本的 package.json
  "peerDependencies": {
    "vite": "^3.0.0 || ^4.0.0 || ^5.0.0",
    "vue": "^2.7.0-0"
  },

pnpm i vite@"^5.0.0" vue@"^2.7.0" @vitejs/plugin-vue2@2.3.1

在 package.json 中添加 scripts:

  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },

新建 vite.config.js

import vue from '@vitejs/plugin-vue2'

export default {
  plugins: [vue()]
}

创建 main.js 等文件

// src/main.js
import Vue from "vue";
import App from "./App.vue";

Vue.config.productionTip = false;
Vue.config.devtools = true;

new Vue({
  el: "#app",
  render: (h) => h(App),
});
// src/App.vue
<template>
  <section>
    {{ message }}
  </section>
</template>

<script setup>
import { ref } from "vue";
const message = ref("模板");
</script>
// index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

eslint

配置 eslint npm init @eslint/config@latest

如有问题可参考 《vscode 中 eslint 无效?npm init 是什么?》


Step 2:搭建脚手架,让一切自动化

npm init、bin

在前言中说了,我的目标是 “执行 npm init lily-cli,就会自动创建项目”。所以有必要了解一下 npm init 这个命令

点这里查看 npm init 官方文档

npm init 有两种用法:

  • npm init 在一连串问题后,根据你的回答自动创建 package.json 文件。-y 可以跳过问题
  • npm init <initializer>:根据指定的 initializer 初始化项目。通过 npx 安装 create-<initializer> 包并执行它的 bin。

在这里插入图片描述

我的脚手架名称是 lily-cli,所以 npm package 名字应该是 create-lily-cli。并且要设置 bin 字段。

简单了解一下 bin 字段,点这里查看官方文档:

在这里插入图片描述
注意:bin 的入口文件必须以 #!/usr/bin/env node 开头,告诉操作系统要用 nodejs 运行此脚本。不然的话,在 npm exec 时会报错 800A03EA:

在这里插入图片描述

初始化项目

  • 新建文件夹 create-lily-cli
  • git init,新建 .gitignore
  • npm init -y
  • 在 package.json 中设置 "type": "module" (个人习惯使用 import/export 语法)
  • 新建 index.js
  • 在 package.json 中设置 "bin": "./index,js"

为了防止歧义,明确一下称呼:

  • Step 1 中创建的 template_vite_vue2_eslint 为 “模板项目”。它是为了给 “脚手架项目” 提供参考的模板
  • Step 2 中创建的 create-lily-cli 为 “脚手架项目”。它的作用是一键生成 “成果项目”
  • 使用 create-lily-cli 脚手架自动生成的,称为 “成果项目”,它应该和 “模板项目” 长得一致

目标功能

  1. 自动生成项目所有文件
  2. 自动安装依赖
  3. 自动初始化 git 并 commit

开发功能

实现思路:
在脚手架项目中新建文件夹 template,把 “模板项目” 的文件都复制到这个文件夹下( .git 文件夹、node_modules 文件夹和 pnpm-lock.yaml 除外)。
编写脚本,使每次执行脚本时复制 /template 下的所有内容到目标路径,这就实现了 功能1:自动生成项目所有文件
功能2和3更简单,让脚本自动执行命令。

需要注意的是,在功能3的 commit 之前,“成果项目” 中必须存在 .gitignore(不然成果项目/node_modules 也会被commit)。
但是 npm 在 publish package 时,不会把 .gitignore 文件上传到 npm 仓库(TODO 这里不具体解释了,以后会写文章专门讨论这个问题)。有两种解决方案:

  1. template/.gitignore 文件改名(比如改成 template/gitignore,去掉最前面的.),这时就可以成功 publish 到 npm 仓库了。在脚本中写代码,对成果项目进行 git 操作前,先把 gitignore 文件的名字改回来
  2. 干脆把 template/.gitignore 文件去掉。在脚本中给成果项目创建 .gitignore 文件

index.js:

#!/usr/bin/env node
import process from "process";
import path from "path";
import { cp, writeFile, rename, rm } from "fs/promises";
import spawn from "cross-spawn"; // 用法同 nodejs 内置的 child_process 模块,但解决了跨平台的兼容性问题
import { fileURLToPath } from "url";
import { dirname } from "path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); // __dirname 当前文件所在目录;process.cwd() 执行命令的目录

async function run() {
  const target_path = path.join(process.cwd(), "lily-template-project");
  await generateFiles(target_path); // 根据模板生成文件
  installDeps(target_path); // 安装依赖
  await initGit(target_path); // 初始化 git
}

run();

async function generateFiles(target_path) {
  const src_path = path.join(__dirname, "template");
  await cp(src_path, target_path, { recursive: true }); // 将模板中的所有文件递归复制到目标路径
}

function installDeps(dirPath) {
  spawn.sync("pnpm i", { stdio: "inherit", cwd: dirPath });
}

async function initGit(dirPath) {
  const spawnOptions = { stdio: "inherit", cwd: dirPath };
  spawn.sync("git init", spawnOptions);
  // 为了解决《npm 在 publish package 时,不会把 .gitignore 文件上传到 npm 仓库》,有两种方案:
  await rename(path.join(dirPath, "gitignore"), path.join(dirPath, ".gitignore")); // 方案1:template中给.gitignore改名。这里再改回来
  // await writeFile(path.join(dirPath, ".gitignore"), "node_modules"); // 方案2:直接用代码创建 .gitignore
  spawn.sync("git add .", spawnOptions);
  spawn.sync("git commit", ["-m", "init project"], spawnOptions);
}

插播:别用 npm link!别用 npm link!别用 npm link
在开发阶段我用 npm link + npx create-lily-cli 进行本地调试。调试完成准备发布,我需要解除本地 link。
我尝试了多种方法: unlinkuninstall -g、清除 npm cache、清除 npx cache,但都清理不掉 npx 中的缓存!(npm 的 link 应该是清理干净了,npm i create-lily-cli 已经不生效了)。
在我 publish 了之后再执行 npx,它还是用的之前本地 link 的版本。我最后是卸载 nodejs 重装才清理掉。。。。
在这里插入图片描述

发布到 npm

npm publish

执行命令

执行 npm init lily-cli,成功!


写这个脚手架是受 @eslint/config 的启发 在这里插入图片描述
之前以为写这类东西很复杂,但是在研究 @eslint/config 源码的时候,发现还蛮简单的,所以才决定自己试试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/707649.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

hw面试总结

在这里给大家推荐一个阿里云的活动&#xff0c;可白嫖一年2h4g服务器 活动链接&#xff1a;https://university.aliyun.com/mobile?clubTaskBizsubTask…11404246…10212…&userCodeks0bglxp 一、漏洞分析 1.SQL注入 原理&#xff1a; 当Web应用向后台数据库传递SQL…

企业服务器上云还是下云哪种比较好?-尚云Sunclouds

如今很多中小企业都面临一个艰难的选择&#xff0c;是要选择将服务器迁移至数据中心托管&#xff08;下云&#xff09;或者直接迁移到云端&#xff08;上云&#xff09;。中小企业是社会发展的中坚力量&#xff0c;他们的特点少而明显&#xff1a;资金少&#xff0c;增长快&…

Perl 语言学习进阶

一、如何深入 要深入学习Perl语言的库和框架&#xff0c;可以按照以下步骤进行&#xff1a; 了解Perl的核心模块&#xff1a;Perl有许多核心模块&#xff0c;它们提供了许多常用的功能。了解这些模块的功能和用法是深入学习Perl的第一步。一些常用的核心模块包括&#xff1a;S…

Postman batch post requests import 双引号问题

初次使用工具中注意事项&#xff1a; 1 定义json参数变量value由于没有注意双引号问题导致run 报400 错误 测试结果总是报400 bad request错误

Python数据库编程指南:连接与操作SQLite与MySQL

目录 一、引言 二、SQLite数据库连接与操作 &#xff08;一&#xff09;安装SQLite库 &#xff08;二&#xff09;建立数据库连接 &#xff08;三&#xff09;执行SQL语句 &#xff08;四&#xff09;注意事项 三、MySQL数据库连接与操作 &#xff08;一&#xff09;安…

量化交易实操指南:从模拟回测到实盘交易的全流程揭秘!

什么是量化交易&#xff1f; 量化交易是一种利用数学、统计学和计算机科学方法&#xff0c;通过构建模型和算法来进行交易决策的方式。它的核心思想是通过系统性的分析和处理大量的历史数据、市场信息和交易规则&#xff0c;以发现市场中的规律和模式&#xff0c;并以此为依据…

虚拟化 之三 详解 jailhouse(ARM 平台)的构建过程、配置及使用

嵌入式平台下,由于资源的限制,通常不具备通用性的 Linux 发行版,各大主流厂商都会提供自己的 Linux 发行版。这个发行版通常是基于某个 Linux 发行版构建系统来构建的,而不是全部手动构建,目前主流的 Linux 发行版构建系统是 Linux 基金会开发的 Yocto 构建系统。 基本环…

LabVIEW开发指针式压力仪表图像识别

系统利用LabVIEW编程实现对指针式压力仪表的读取&#xff0c;通过相机、光源、固定支架等硬件捕捉仪表图像&#xff0c;并通过图像识别技术解析压力值。系统分为两个阶段&#xff1a;第一阶段固定相机更换仪表&#xff0c;第二阶段移动相机识别多个固定仪表。本文介绍硬件选择、…

可再生能源的未来——Kompas.ai如何助力绿色发展

引言 在全球气候变化和能源危机的背景下&#xff0c;可再生能源逐渐成为能源发展的重要方向。本文将探讨可再生能源的发展趋势&#xff0c;并介绍Kompas.ai如何通过AI技术助力绿色发展的实现。 可再生能源的发展及其重要性 可再生能源是指通过自然资源产生的能源&#xff0c;…

ubuntu20.04设置共享文件夹

ubuntu20.04设置共享文件夹 一&#xff0c;简介二&#xff0c;操作步骤1&#xff0c;设置Windows下的共享目录2&#xff0c;挂载共享文件夹3&#xff0c;测试是否挂载成功 一&#xff0c;简介 在公司电脑上&#xff0c;使用samba设置共享文件夹&#xff0c;IT安全部门权限不通…

Linux内核驱动入门 编译环境搭建、编译内核

文章目录 前言搭建内核驱动编译环境下载交叉编译工具编译内核minicom工具使用找不到ttyUSB设备问题编译内核编译报错解决小坑编译选项说明 从零开始的驱动程序 前言 哎…有时候我都不知道自己是干啥的 说是运维吧&#xff0c;docker不会&#xff0c;k8s不会&#xff1b;说是驱…

File及典型案例

File File对象表示一个路径&#xff0c;可以是文件的路径&#xff0c;也可以是文件夹的路径 这个路径可以是存在的&#xff0c;也允许不存在 常见的构造方法 图来自黑马程序员网课 package com.lazyGirl.filedemo;import java.io.File;public class Demo1 {public static vo…

小程序开发,网站搭建,手机app开发,管理系统开发

小程序开发&#xff0c;网站搭建&#xff0c;手机app开发&#xff0c;管理系统开发

grpc代理服务的实现(一)

最近公司需要无感知基于服务代号来实现通信, 并监控和管理通信连接&#xff0c;目前公司使用的是如下的逻辑(当然逻辑简化了&#xff0c;但是思想不变) 目录 简单的原理图代理服务的实现创建 tls tcp 服务, 用于grpc client 和 grpc service 通信保存 与 代理服务建立的 grpc …

Java多线程编程与并发处理

引言 在现代编程中&#xff0c;多线程和并发处理是提高程序运行效率和资源利用率的重要方法。Java提供了丰富的多线程编程支持&#xff0c;包括线程的创建与生命周期管理、线程同步与锁机制、并发库和高级并发工具等。本文将详细介绍这些内容&#xff0c;并通过表格进行总结和…

建议收藏!AIGC绘画基础,Midjourney风格码style reference code策展汇总合集

自打Midjourney推出风格码style reference code以来&#xff0c;各路大神都在积极“挖矿”&#xff0c;不断地使用sref random后缀参数来寻找不同风格。 得益于Midjourney爱好者们“分布式挖矿”的力量&#xff0c;很多Midjourney风格被测试出来。我已经把前1000个风格码看了一…

R语言绘制三变量分区地图

参考资料&#xff1a; https://mp.weixin.qq.com/s/5c7gpO2mJ2BqJevePJz3CQ tricolore包教程&#xff1a;https://github.com/jschoeley/tricolore 学习笔记&#xff1a;Ternary choropleth maps 1、测试实例 代码&#xff1a; library(ggplot2) library(rnaturalearthdata) …

使用ant-design/cssinjs向plasmo浏览器插件的内容脚本content中注入antd的ui组件样式

之前写过一篇文章用来向content内容脚本注入antd的ui&#xff1a;https://xiaoshen.blog.csdn.net/article/details/136418199&#xff0c;但是方法就是比较繁琐&#xff0c;需要将antd的样式拷贝出来&#xff0c;然后贴到一个单独的css样式文件中&#xff0c;然后引入到内容脚…

Apple - Metal Programming Guide

本文翻译整理自&#xff1a;Metal Programming Guide&#xff08;更新日期&#xff1a;2016-12-12 https://developer.apple.com/library/archive/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP400142…

next.js开发中页面回退时报Unhandled Runtime ErrorTypeError destroy is not a function

Next.js开发中页面回退时报Unhandled Runtime Error:TypeError: destroy is not a function 问题描述 在Next.js开发中&#xff0c;从A页面跳转到B页面&#xff0c;再使用浏览器回退到A页面时报上述错误&#xff1a; 错误原因 是因为在B页面里&#xff0c;在使用useEffect时…