幽灵依赖是什么,pnpm出现的意义,使用pnpm创建一个vue3项目

news2024/12/23 1:55:54

什么是幽灵依赖(幻影依赖)

比如我们创建一个全新的vue3项目
在这里插入图片描述
然后我们正常地通过npm install来下载依赖
然后我们发现,node_ modules文件夹下的很多依赖,我们在package.json中明明没去声明却都下载下来了
在这里插入图片描述

那么这些没声明却下载的依赖就是幽灵依赖(幻影依赖)

这种现象出现的原因,可能是一个库依赖另一个库

因此,我们可以在项目中去使用一个我们并没有声明的库,比如lodash

在这里插入图片描述
但是这样的话,会出现几个问题

版本问题

在这里插入图片描述
比如一个项目用的A这个库,版本是v1,

然后A这个库依赖B库,版本也是v1

B这个库就是我们没有声明的一个库,但是我们仍然在项目中去进行使用

但是如果有一天,我们对A这个库进行了升级,比如说升级到了v2的版本,然后它可能需要对应B库的v2版本,于是B库也跟着莫名其妙地进行升级了,而B库升级之后,它里面的api可能会发生变动,那么可能会导致我们之前的用B库的代码出现问题。

这就是幽灵依赖的一种情况,当然,可能会有更复杂的情况

这个时候,我们可能不好排错和处理

依赖丢失

还有一种依赖丢失的情况
在这里插入图片描述
现在A是一个开发时依赖,也就是到了生产环境里,是不会安装A这个依赖的,
那么B也就不会安装,但是在开发的时候却使用了B,但是生成的时候B却没有了,所以这会发生依赖丢失的问题

为什么会产生这个问题

我们开发的时候会用到很多的包,包与包之间会形成一些依赖关系,比如依赖数依赖图

但是npm这个包管理器,使用的是文件结构,而文件结构是一个树结构,这样的话,结构不匹配。
在这里插入图片描述
这样的的话会导致重复的依赖下载下来,比如上面的D

所以后来出现了一个包管理工具yarn,它通过拍平的方式解决了这个问题
在这里插入图片描述
那么这样怎么体现出包之间的依赖关系呢

nodejs有一个查询包的流程

就是在import或者require的时候,它找不到的话,会往上去找

yarn这样做的确解决了结构问题(现在新的npm也是yarn的处理方式),但是却产生了幽灵依赖

pnpm

在这里插入图片描述
pnpm也是一个包管理工具,它解决了幽灵依赖的问题

它把所有的包。存到一个仓库文件夹里面,然后在node_modules里面用正常的树结构,来表达包依赖

但是它这么做,不会有重复项,因为它使用的链接的方式来处理,也就是说
在这里插入图片描述
这几个并不占空间,它只是一个链接

在这里插入图片描述
这样问题就解决了

现在我们把之前的依赖删除,用pnpm来进行安装
在这里插入图片描述
这个.pnpm文件就是它的仓库

.pnpm称为虚拟存储目录,以平铺的形式储存着所有的项目依赖包,每个依赖包都可以通过.pnpm/@/node_modules/路径找到实际位置。

在这里插入图片描述
剩下的就是在package.json中声明的依赖,比如vite、vue采用的叫做符号链接

软链接和硬链接

在这里插入图片描述
硬链接

我们的文件数据,都是存在磁盘上的,我们创建一个文件,就给它分配一段磁盘空间,文件是一个指针,指针指向这个磁盘空间,可以通过文件A创建一个硬链接文件B,如果是通过硬链接来创建的话,那么B的指针和A是一样的,他也是同样指向这个磁盘空间,这样就是两个文件,共用一块磁盘空间,这样在硬链接的前提下,把文件A干掉了,不会影响文件B

软链接

软链接类似于快捷方式,它和硬链接的区别是,此处的文件A通过软链接创建文件B,文件B指向的是文件A,而不是磁盘空间,相当于B是A的一个快捷方式

pnpm中软链接和硬链接都用到了

pnpm使用符号链接Symbolic link(软链接)来创建依赖项的嵌套结构,将项目的直接依赖符号链接到node_modules的根目录,直接依赖的实际位置在.pnpm/<name>@<version>/node_modules/<name>,依赖包中的每个文件再硬链接(Hard link)到.pnpm store

pnpm的基本使用

安装

npm install -g pnpm

通过下述命令查看已安装的pnpm的版本

pnpm -v

安装依赖

pnpm install xxx

运行package.json中定义的scripts脚本

pnpm run xxx

pnpm管理node环境

之前我们切换node版本可能需要借助nvm等版本管理工具,但是pnpm就可以实现nvm的功能

本地安装并使用:pnpm env use <node版本号>
全局安装并使用:pnpm env use --global <node版本号>

但是在此前,你需要卸载你已有的nodejs,否则你会报这么一个错误
在这里插入图片描述
卸载完之后
windows使用PowerShell:

iwr https://get.pnpm.io/install.ps1 -useb | iex

MacOS

curl -fsSL https://get.pnpm.io/install.sh | sh -

执行命令安装成功后后会看到Setup complete. Open a new terminal to start using pnpm.

这时我们需要重新打开命令行终端,输入pnpm -v 即可查看pnpm版本号,在此表示安装成功

安装 LTS(长期稳定版) 版本的 Node:

pnpm env use --global lts

// global可简写为g,即上边命令可简写为:

pnpm env use --g lts

执行命令会得到提示:

Fetching Node.js 18.16.0 ...
Node.js 18.16.0 is activated
C:\Users\xxx\AppData\Local\pnpm\node.exe -> C:\Users\xxx\AppData\Local\pnpm\nodejs\18.16.0\node.exe

这时我们输入node -v 可查看node版本号,即表示node已安装成功

安装指定版本的Node:

pnpm env use --g 16

执行命令会得到提示:

Fetching Node.js 16.20.0 ...
Node.js 16.20.0 is activated
C:\Users\xxx\AppData\Local\pnpm\node.exe -> C:\Users\xxx\AppData\Local\pnpm\nodejs\16.20.0\node.exe

注意:这里输入的版本号为16,则会下载v16的最后一个版本,也就是16.20.0,你也可以指定次版本号,例如pnpm env use --global 16.18.2 ,可用的版本号列表执行pnpm env list --remote 命令查看

安装最新版本的 Node.js:

pnpm env use --g latest

查看本地安装的Node版本

pnpm env list

或

pnpm env ls

执行命令会看到:

  16.20.0
  18.16.0
* 20.3.0

星号表示当前使用的Node版本

查看服务器可用的Node版本

pnpm env list --remote

移除本地已经安装Node版本

pnpm env remove --g 16.20.0

执行命令会提示:

Node.js 16.20.0 is removed
C:\Users\55856\AppData\Local\pnpm\nodejs\16.20.0

这时我们再使用pnpm env list 命令查看,会发现16.20.0已被删除:

18.16.0
* 20.3.0

pnpm对monorepo的支持

这一点在之前的文章中有详细说过
Pnpm实现Monorepo风格项目搭建

使用pnpm创建一个vue3项目

pnpm创建项目

pnpm create vite

集成eslint

pnpm i eslint -D

生成配置文件:.eslint.cjs

npx eslint --init

在这里插入图片描述
在这里插入图片描述
.eslint.cjs配置文件含义

module.exports = {
   //运行环境
    "env": { 
        "browser": true,//浏览器端
        "es2021": true,//es2021
    },
    //规则继承
    "extends": [ 
       //全部规则默认是关闭的,这个配置项开启推荐规则,推荐规则参照文档
       //比如:函数不能重名、对象不能出现重复key
        "eslint:recommended",
        //vue3语法规则
        "plugin:vue/vue3-essential",
        //ts语法规则
        "plugin:@typescript-eslint/recommended"
    ],
    //要为特定类型的文件指定处理器
    "overrides": [
    ],
    //指定解析器:解析器
    //Esprima 默认解析器
    //Babel-ESLint babel解析器
    //@typescript-eslint/parser ts解析器
    "parser": "@typescript-eslint/parser",
    //指定解析器选项
    "parserOptions": {
        "ecmaVersion": "latest",//校验ECMA最新版本
        "sourceType": "module"//设置为"script"(默认),或者"module"代码在ECMAScript模块中
    },
    //ESLint支持使用第三方插件。在使用插件之前,您必须使用npm安装它
    //该eslint-plugin-前缀可以从插件名称被省略
    "plugins": [
        "vue",
        "@typescript-eslint"
    ],
    //eslint规则
    "rules": {
    }
}

vue3环境代码校验插件

# 让所有与prettier规则存在冲突的Eslint rules失效,并使用prettier进行代码检查
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
# 运行更漂亮的Eslint,使prettier规则优先级更高,Eslint优先级低
"eslint-plugin-prettier": "^4.2.1",
# vue.js的Eslint插件(查找vue语法错误,发现错误指令,查找违规风格指南
"eslint-plugin-vue": "^9.9.0",
# 该解析器允许使用Eslint校验所有babel code
"@babel/eslint-parser": "^7.19.1",

安装

pnpm install -D eslint-plugin-import eslint-plugin-vue eslint-plugin-node eslint-plugin-prettier eslint-config-prettier eslint-plugin-node @babel/eslint-parser

修改.eslintrc.cjs配置文件

// @see https://eslint.bootcss.com/docs/rules/

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
    jest: true,
  },
  /* 指定如何解析语法 */
  parser: 'vue-eslint-parser',
  /** 优先级低于 parse 的语法解析配置 */
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    parser: '@typescript-eslint/parser',
    jsxPragma: 'React',
    ecmaFeatures: {
      jsx: true,
    },
  },
  /* 继承已有的规则 */
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-essential',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
  ],
  plugins: ['vue', '@typescript-eslint'],
  /*
   * "off"0    ==>  关闭规则
   * "warn"1   ==>  打开的规则作为警告(不影响代码执行)
   * "error"2  ==>  规则作为一个错误(代码不能执行,界面报错)
   */
  rules: {
    // eslint(https://eslint.bootcss.com/docs/rules/)
    'no-var': 'error', // 要求使用 let 或 const 而不是 var
    'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-unexpected-multiline': 'error', // 禁止空余的多行
    'no-useless-escape': 'off', // 禁止不必要的转义字符

    // typeScript (https://typescript-eslint.io/rules)
    '@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量
    '@typescript-eslint/prefer-ts-expect-error': 'error', // 禁止使用 @ts-ignore
    '@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
    '@typescript-eslint/no-non-null-assertion': 'off',
    '@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
    '@typescript-eslint/semi': 'off',

    // eslint-plugin-vue (https://eslint.vuejs.org/rules/)
    'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
    'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用
    'vue/no-mutating-props': 'off', // 不允许组件 prop的改变
    'vue/attribute-hyphenation': 'off', // 对模板中的自定义组件强制执行属性命名样式
  },
}

eslintignore忽略文件

dist
node_modules
"scripts": {
        "lint": "eslint src",
        "fix": "eslint src --fix",
}

配置prettier

    pnpm install -D eslint-plugin-prettier prettier eslint-config-prettier

prettierrc.json添加规则
“singleQuote”: true 表示使用单引号代替双引号。
“semi”: false 表示不使用分号。
“bracketSpacing”: true 表示在对象字面量声明中在括号之间打印空格。
“htmlWhitespaceSensitivity”: “ignore” 表示在HTML模板中忽略空格敏感度。
“endOfLine”: “auto” 表示自动选择操作系统特定的行结束符。
“trailingComma”: “all” 表示尽可能使用尾随逗号。
“tabWidth”: 2 表示使用两个空格作为一个制表符的宽度。

{
  "singleQuote": true,
  "semi": false,
  "bracketSpacing": true,
  "htmlWhitespaceSensitivity": "ignore",
  "endOfLine": "auto",
  "trailingComma": "all",
  "tabWidth": 2
}

prettierignore忽略文件

/dist/*
/html/*
.local
/node_modules/**
**/*.svg
**/*.sh
/public/*

通过pnpm run lint去检测语法,如果出现不规范格式,通过pnpm run fix 修改
在这里插入图片描述
在这里插入图片描述

配置stylelint

stylelint为css的lint工具。可格式化css代码,检查css语法错误与不合理的写法,指定css书写顺序等。

pnpm add sass sass-loader stylelint postcss postcss-scss postcss-html stylelint-config-prettier stylelint-config-recess-order stylelint-config-recommended-scss stylelint-config-standard stylelint-config-standard-vue stylelint-scss stylelint-order stylelint-config-standard-scss -D

.stylelintrc.cjs配置文件

// @see https://stylelint.bootcss.com/

module.exports = {
  extends: [
    'stylelint-config-standard', // 配置stylelint拓展插件
    'stylelint-config-html/vue', // 配置 vue 中 template 样式格式化
    'stylelint-config-standard-scss', // 配置stylelint scss插件
    'stylelint-config-recommended-vue/scss', // 配置 vue 中 scss 样式格式化
    'stylelint-config-recess-order', // 配置stylelint css属性书写顺序插件,
    'stylelint-config-prettier', // 配置stylelint和prettier兼容
  ],
  overrides: [
    {
      files: ['**/*.(scss|css|vue|html)'],
      customSyntax: 'postcss-scss',
    },
    {
      files: ['**/*.(html|vue)'],
      customSyntax: 'postcss-html',
    },
  ],
  ignoreFiles: [
    '**/*.js',
    '**/*.jsx',
    '**/*.tsx',
    '**/*.ts',
    '**/*.json',
    '**/*.md',
    '**/*.yaml',
  ],
  /**
   * null  => 关闭该规则
   * always => 必须
   */
  rules: {
    'value-keyword-case': null, // 在 css 中使用 v-bind,不报错
    'no-descending-specificity': null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
    'function-url-quotes': 'always', // 要求或禁止 URL 的引号 "always(必须加上引号)"|"never(没有引号)"
    'no-empty-source': null, // 关闭禁止空源码
    'selector-class-pattern': null, // 关闭强制选择器类名的格式
    'property-no-unknown': null, // 禁止未知的属性(true 为不允许)
    'block-opening-brace-space-before': 'always', //大括号之前必须有一个空格或不能有空白符
    'value-no-vendor-prefix': null, // 关闭 属性值前缀 --webkit-box
    'property-no-vendor-prefix': null, // 关闭 属性前缀 -webkit-mask
    'selector-pseudo-class-no-unknown': [
      // 不允许未知的选择器
      true,
      {
        ignorePseudoClasses: ['global', 'v-deep', 'deep'], // 忽略属性,修改element默认样式的时候能使用到
      },
    ],
  },
}

.stylelintignore忽略文件

/node_modules/*
/dist/*
/html/*
/public/*
"scripts": {
"lint:style": "stylelint src/**/*.{css,scss,vue} --cache --fix"
}

最后配置统一的prettier来格式化我们的js和css,html代码

 "scripts": {
    "dev": "vite --open",
    "build": "vue-tsc && vite build",
    "preview": "vite preview",
    "lint": "eslint src",
    "fix": "eslint src --fix",
    "format": "prettier --write \"./**/*.{html,vue,ts,js,json,md}\"",
    "lint:eslint": "eslint src/**/*.{ts,vue} --cache --fix",
    "lint:style": "stylelint src/**/*.{css,scss,vue} --cache --fix"
  },

当我们运行pnpm run format的时候,会把代码直接格式化
在这里插入图片描述

去除console.log

通过terser工具来去除console.log
正常打包
在这里插入图片描述
加上terser配置
这是webpack

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  terser:{
    terserOptions: {
      compress: {
        // 移除console.log
        drop_console: true,
        // 移除debugger
        drop_debugger: true
      }
    }
  }
})

这是vite,使用vite之前需要安装rollup-plugin-terser模块:

pnpm install rollup-plugin-terser --save-dev

在这里插入图片描述

import { terser } from 'rollup-plugin-terser'
  plugins: [vue(), terser()],

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL-游标-查询

/***DB版本&#xff1a;SQL Server 2022***/ --切换数据库 use MyDatabase--创建游标(scroll&#xff1a;滚动游标) declare mycur cursor scroll for select EmpNo from Employee--打开游标 open mycur --提取第一行 fetch first from mycur --提取最后一行 fetch last from m…

ansible自动化安装及简单操作

目录 一、运行机制 二、安装 1.下载ansible 2.配置免密 3.修改配置文件 4.创建主机清单 5.远程安装 6.远程卸载 一、运行机制 Ansible&#xff1a; ansible的核心模块 Host Inventory&#xff1a;主机清单&#xff0c;也就是被管理的主机列表 Playbooks&…

实战打靶集锦-021-glasgowsmile

提示&#xff1a;本文记录了博主的一次曲折的打靶经历。 目录 1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 手工访问4.2 目录枚举4.3 手工探查4.4 搜索EXP4.5 joomlascan4.6 用户猜测与密码爆破4.7 构建反弹shell 5. 提权5.1 优化shell5.2 枚举系统信息5.3 探查/etc/pass…

虚拟机VMware+Ubuntu配置DPDK环境并运行Helloworld

虚拟机VMwareUbuntu配置DPDK环境并运行Helloworld 文章目录 虚拟机VMwareUbuntu配置DPDK环境并运行Helloworld安装虚拟机虚拟机中安装DPDK运行Helloworld 首先需要强调的是&#xff0c;版本的影响很大&#xff0c;有可能会因为版本不匹配而导致无法成功配置DPDK环境。 安装虚拟…

【Leetcode -637.二叉树的层平均值 -671.二叉树中第二小的节点】

Leetcode Leetcode -637.二叉树的层平均值Leetcode -671.二叉树中第二小的节点 Leetcode -637.二叉树的层平均值 题目&#xff1a;给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10^(- 5) 以内的答案可以被接受。 示例 1&#xff1…

TCP服务器的C#实现

1、TCP实现类 internal class TcpServer{public Socket ServerSocket { get; set; }public Dictionary<string,Socket> Sockets { get; set; } new Dictionary<string,Socket>();public byte[] SendBuffer { get; set; }public byte[] ReceiveBuffer { get; set; …

Qt消息对话框

一、头文件及类型 #include<QMessageBox> 二、错误、信息、提示、警告演示 错误对话框 QMessageBox::critical(this,"critical","错误"); 信息对话框 QMessageBox::information(this,"info","信息"); 提问对话框 if(QMessageBo…

发布自己的第一个抖音小程序

结构与微信小程序一样 内嵌H5网页&#xff0c;适用于任何平台&#xff0c;同样也是使用web-view组件 <web-view src"https://some-domain/some/path"></web-view> 相比起来&#xff0c;它比微信小程序更加简化&#xff0c;开发会更方便了。 API查询地…

超越Java 7,迎接Java 8时代!掌握这些新特性提升你的编程技能!

大家好&#xff0c;我是小米&#xff0c;一个热衷于技术分享的小伙伴。今天&#xff0c;我将向大家介绍Java 8中的一些新特性。Java 8作为一次重大更新&#xff0c;引入了许多令人激动的新功能&#xff0c;让我们的编码变得更加简洁高效。接下来&#xff0c;我们将详细介绍这些…

【暂时解决】radio单选框的change事件执行两次

项目场景&#xff1a; 简单的单选框场景 选择国内地区&#xff0c;省市县的下拉框就显示&#xff0c;选择国外地区就隐藏。 问题描述 当我使用radio的change事件时&#xff0c;会执行两次 javascript&#xff1a; $(input[typeradio][nameoptionsRadios]).change(function …

黑产科普丨揭秘游戏黑灰产业链

自今年起&#xff0c;游戏版号已恢复常态化发放&#xff0c;游戏行业在官方发文肯定、重获资本青睐、AI降本增效等多方助力下持续回暖。暑期档将至&#xff0c;游戏厂商为了抢占更多的市场份额&#xff0c;占据更多的玩家视野&#xff0c;将有大量的游戏选择在这个时间上线。 …

datax-Oracle新增writeMode支持

1.在com.alibaba.datax.plugin.writer.oraclewriter.OracleWriter中注释此内容,以让oracle支持writeMode模式 2.在com.alibaba.datax.plugin.rdbms.writer.util.WriterUtil中,增加对oracle的判断,将getWriteTemplate修改为如下内容 public static String getWriteTemplate(List…

在文件夹中获取某个文件的绝对路径

#!/bin/bash -lpathfind $(pwd) -name *.ipaecho ${path}写成下面这样也是可以的 path$(find $(pwd) -name *.ipa)如图所示&#xff0c;Export 文件夹下有.ipa文件&#xff0c;我们目前想获取.ipa文件的绝对路径 执行结果如下 192:Jenkins liubo$ cd /Users/liubo/Desktop/…

C# 通过委托实现多个窗口之间的传值

之前用qt写的时候&#xff0c;都有信号和槽来实现&#xff0c;用C#的话应该也有类似的 大概实现的是我在父窗口当中new了两个子窗口&#xff0c;这个两个子窗口都可以将处理完的数据传递给父窗口&#xff0c;并且两个子窗口通过父窗口进行通信。 我这就按上面窗口名称来说明代…

pipeline实现二次还原

通过mode参数确定是否发布还是回滚&#xff0c;在满足rollback条件下&#xff0c;列举出我们的所有的备份的目录&#xff0c;根据回滚条件选择索要回滚的目录(目录是根据时间戳来判断创建的文件) pipeline {agent anyparameters {choice(name: mode, choices: [deploy,rollbac…

HA 自动化-通知提醒

配置->场景自动化->创建自动化 notify.notify

Gitlab群组及项目仓库搭建

1、新建群组 2、新建项目 3、克隆到Visualstudio 复制克隆地址&#xff0c;克隆到本地 这里会让你登录账号 可以添加成员并邀请ta进项目组 从已注册用户列表中选择 4、Git工作流 回顾一下Git工作流&#xff0c;工程人员只需要从Develop分支新建自己的分支即可。分支命名以姓名…

设计模式学习之抽象工厂模式

设计模式系列往期文章 设计模式学习之策略模式设计模式学习之策略模式在前端的应用设计模式学习之简单工厂模式设计模式学习之工厂方法模式 如果你已经理解了工厂方法模式&#xff0c;那你能够很快的明白抽象工厂模式。 温习&#xff1a;什么是工厂方法模式 我们先温习一下…

【面试题19】B-Tree和B+Tree的区别,以及B+Tree在MySQL中的应用

文章目录 一、前言二、关于B-Tree和B Tree2.1 B-Tree2.2 BTree 三、B Tree与B Tree的差异3.1 叶子节点的差异3.2 数据访问的差异3.3 范围查询的差异 四、Mysql中BTree的应用场景4.1 主键索引4.2 唯一索引4.3 普通索引 五、MySQL为什么使用BTree来做索引&#xff1f;总结 一、前…

【网络安全】IP地址定位技术的应用场景

随着科技的不断发展&#xff0c;网络空间已经成为人们生活中重要的一部分。而其中&#xff0c;IP地址定位技术又是网络空间不可或缺的一部分。IP地址定位技术是一种可以根据IP地址确定用户位置的技术这项技术不仅可以用于个人定位&#xff0c;也可以使用在商业领域、网络安全和…