Vue 团队公开快如闪电的全新脚手架工具,未来将替代 Vue-CLI,才300余行代码,学它!...

2023-11-03

1. 前言

大家好,我是若川。欢迎关注我的公众号若川视野源码共读活动ruochuan12

想学源码,极力推荐之前我写的《学习源码整体架构系列》jQueryunderscorelodashvuexsentryaxiosreduxkoavue-devtoolsvuex4koa-composevue-next-releasevue-this等十余篇源码文章。

美国时间 2021 年 10 月 7 日早晨,Vue 团队等主要贡献者举办了一个 Vue Contributor Days 在线会议,蒋豪群[1](知乎胖茶[2],Vue.js 官方团队成员,Vue-CLI 核心开发),在会上公开了`create-vue`[3],一个全新的脚手架工具。

create-vue使用npm init vue@next一行命令,就能快如闪电般初始化好基于viteVue3项目。

本文就是通过调试和大家一起学习这个300余行的源码。

阅读本文,你将学到:

1. 学会全新的官方脚手架工具 create-vue 的使用和原理
2. 学会使用 VSCode 直接打开 github 项目
3. 学会使用测试用例调试源码
4. 学以致用,为公司初始化项目写脚手架工具。
5. 等等

2. 使用 npm init vue@next 初始化 vue3 项目

create-vue github README[4]上写着,An easy way to start a Vue project。一种简单的初始化vue项目的方式。

npm init vue@next

估计大多数读者,第一反应是这样竟然也可以,这么简单快捷?

忍不住想动手在控制台输出命令,我在终端试过,见下图。

ff34aafecca8451782b3d485ea71f8c3.png
npm init vue@next

最终cd vue3-projectnpm installnpm run dev打开页面http://localhost:3000[5]

0cacb1d47e454fe0a2faac6ef3d40468.png
初始化页面

2.1 npm init && npx

为啥 npm init 也可以直接初始化一个项目,带着疑问,我们翻看 npm 文档。

npm init[6]

npm init 用法:

npm init [--force|-f|--yes|-y|--scope]
npm init <@scope> (same as `npx <@scope>/create`)
npm init [<@scope>/]<name> (same as `npx [<@scope>/]create-<name>`)

npm init <initializer> 时转换成npx命令:

  • npm init foo -> npx create-foo

  • npm init @usr/foo -> npx @usr/create-foo

  • npm init @usr -> npx @usr/create

看完文档,我们也就理解了:

# 运行
npm init vue@next
# 相当于
npx create-vue@next

我们可以在这里create-vue[7],找到一些信息。或者在npm create-vue[8]找到版本等信息。

其中@next是指定版本,通过npm dist-tag ls create-vue命令可以看出,next版本目前对应的是3.0.0-beta.6

npm dist-tag ls create-vue
- latest: 3.0.0-beta.6
- next: 3.0.0-beta.6

发布时 npm publish --tag next 这种写法指定 tag。默认标签是latest

可能有读者对 npx 不熟悉,这时找到阮一峰老师博客 npx 介绍[9]、nodejs.cn npx[10]

npx 是一个非常强大的命令,从 npm 的 5.2 版本(发布于 2017 年 7 月)开始可用。

简单说下容易忽略且常用的场景,npx有点类似小程序提出的随用随走。

轻松地运行本地命令

node_modules/.bin/vite -v
# vite/2.6.5 linux-x64 node-v14.16.0

# 等同于
# package.json script: "vite -v"
# npm run vite

npx vite -v
# vite/2.6.5 linux-x64 node-v14.16.0

使用不同的 Node.js 版本运行代码某些场景下可以临时切换 node 版本,有时比 nvm 包管理方便些。

npx node@14 -v
# v14.18.0

npx -p node@14 node -v 
# v14.18.0

无需安装的命令执行

# 启动本地静态服务
npx http-server
# 无需全局安装
npx @vue/cli create vue-project
# @vue/cli 相比 npm init vue@next npx create-vue@next 很慢。

# 全局安装
npm i -g @vue/cli
vue create vue-project
d0c2c92db8d148cd440835d9214b1ed4.png
npx vue-cli

npm init vue@nextnpx create-vue@next) 快的原因,主要在于依赖少(能不依赖包就不依赖),源码行数少,目前index.js只有300余行。

3. 配置环境调试源码

3.1 克隆 create-vue 项目

本文仓库地址 create-vue-analysis[11],求个star~

# 可以直接克隆我的仓库,我的仓库保留的 create-vue 仓库的 git 记录
git clone https://github.com/lxchuan12/create-vue-analysis.git
cd create-vue-analysis/create-vue
npm i

当然不克隆也可以直接用 VSCode 打开我的仓库。https://open.vscode.dev/lxchuan12/create-vue-analysis

顺带说下:我是怎么保留 create-vue 仓库的 git 记录的。

# 在 github 上新建一个仓库 `create-vue-analysis` 克隆下来
git clone https://github.com/lxchuan12/create-vue-analysis.git
cd create-vue-analysis
git subtree add --prefix=create-vue https://github.com/vuejs/create-vue.git main
# 这样就把 create-vue 文件夹克隆到自己的 git 仓库了。且保留的 git 记录

关于更多 git subtree,可以看Git Subtree 简明使用手册[12]

3.2 package.json 分析

// create-vue/package.json
{
  "name": "create-vue",
  "version": "3.0.0-beta.6",
  "description": "An easy way to start a Vue project",
  "type": "module",
  "bin": {
    "create-vue": "outfile.cjs"
  },
}

bin指定可执行脚本。也就是我们可以使用 npx create-vue 的原因。

outfile.cjs 是打包输出的JS文件

{
  "scripts": {
    "build": "esbuild --bundle index.js --format=cjs --platform=node --outfile=outfile.cjs",
    "snapshot": "node snapshot.js",
    "pretest": "run-s build snapshot",
    "test": "node test.js"
  },
}

执行 npm run test 时,会先执行钩子函数 pretestrun-s 是 npm-run-all[13] 提供的命令。run-s build snapshot 命令相当于 npm run build && npm run snapshot

根据脚本提示,我们来看 snapshot.js 文件。

3.3 生成快照 snapshot.js

这个文件主要作用是根据const featureFlags = ['typescript', 'jsx', 'router', 'vuex', 'with-tests'] 组合生成31种加上 default 共计 32种 组合,生成快照在 playground目录。

因为打包生成的 outfile.cjs 代码有做一些处理,不方便调试,我们可以修改为index.js便于调试。

// 路径 create-vue/snapshot.js
const bin = path.resolve(__dirname, './outfile.cjs')
// 改成 index.js 便于调试
const bin = path.resolve(__dirname, './index.js')

我们可以在forcreateProjectWithFeatureFlags 打上断点。

createProjectWithFeatureFlags其实类似在终端输入如下执行这样的命令

node ./index.js --xxx --xxx --force
function createProjectWithFeatureFlags(flags) {
  const projectName = flags.join('-')
  console.log(`Creating project ${projectName}`)
  const { status } = spawnSync(
    'node',
    [bin, projectName, ...flags.map((flag) => `--${flag}`), '--force'],
    {
      cwd: playgroundDir,
      stdio: ['pipe', 'pipe', 'inherit']
    }
  )

  if (status !== 0) {
    process.exit(status)
  }
}

// 路径 create-vue/snapshot.js
for (const flags of flagCombinations) {
  createProjectWithFeatureFlags(flags)
}

调试VSCode打开项目,VSCode高版本(1.50+)可以在 create-vue/package.json => scripts => "test": "node test.js"。鼠标悬停在test上会有调试脚本提示,选择调试脚本。如果对调试不熟悉,可以看我之前的文章koa-compose

调试时,大概率你会遇到:create-vue/index.js 文件中,__dirname 报错问题。可以按照如下方法解决。在 import 的语句后,添加如下语句,就能愉快的调试了。

// 路径 create-vue/index.js
// 解决办法和nodejs issues
// https://stackoverflow.com/questions/64383909/dirname-is-not-defined-in-node-14-version
// https://github.com/nodejs/help/issues/2907

import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

接着我们调试 index.js 文件,来学习。

4. 调试 index.js 主流程

回顾下上文 npm init vue@next 初始化项目的。

4dfac8627c39d70d8924629dc9152729.png
npm init vue@next

单从初始化项目输出图来看。主要是三个步骤。

1. 输入项目名称,默认值是 vue-project
2. 询问一些配置 渲染模板等
3. 完成创建项目,输出运行提示
async function init() {
  // 省略放在后文详细讲述
}

// async 函数返回的是Promise 可以用 catch 报错
init().catch((e) => {
  console.error(e)
})

4.1 解析命令行参数

// 返回运行当前脚本的工作目录的路径。
const cwd = process.cwd()
// possible options:
// --default
// --typescript / --ts
// --jsx
// --router / --vue-router
// --vuex
// --with-tests / --tests / --cypress
// --force (for force overwriting)
const argv = minimist(process.argv.slice(2), {
    alias: {
        typescript: ['ts'],
        'with-tests': ['tests', 'cypress'],
        router: ['vue-router']
    },
    // all arguments are treated as booleans
    boolean: true
})

minimist[14]

简单说,这个库,就是解析命令行参数的。看例子,我们比较容易看懂传参和解析结果。

$ node example/parse.js -a beep -b boop
{ _: [], a: 'beep', b: 'boop' }

$ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz
{ _: [ 'foo', 'bar', 'baz' ],
  x: 3,
  y: 4,
  n: 5,
  a: true,
  b: true,
  c: true,
  beep: 'boop' }

比如

npm init vue@next --vuex --force

4.2 如果设置了 feature flags 跳过 prompts 询问

这种写法方便代码测试等。直接跳过交互式询问,同时也可以省时间。

// if any of the feature flags is set, we would skip the feature prompts
  // use `??` instead of `||` once we drop Node.js 12 support
  const isFeatureFlagsUsed =
    typeof (argv.default || argv.ts || argv.jsx || argv.router || argv.vuex || argv.tests) ===
    'boolean'

// 生成目录
  let targetDir = argv._[0]
  // 默认 vue-projects
  const defaultProjectName = !targetDir ? 'vue-project' : targetDir
  // 强制重写文件夹,当同名文件夹存在时
  const forceOverwrite = argv.force

4.3 交互式询问一些配置

如上文npm init vue@next 初始化的图示

  • 输入项目名称

  • 还有是否删除已经存在的同名目录

  • 询问使用需要 JSX Router vuex cypress 等。

let result = {}

  try {
    // Prompts:
    // - Project name:
    //   - whether to overwrite the existing directory or not?
    //   - enter a valid package name for package.json
    // - Project language: JavaScript / TypeScript
    // - Add JSX Support?
    // - Install Vue Router for SPA development?
    // - Install Vuex for state management? (TODO)
    // - Add Cypress for testing?
    result = await prompts(
      [
        {
          name: 'projectName',
          type: targetDir ? null : 'text',
          message: 'Project name:',
          initial: defaultProjectName,
          onState: (state) => (targetDir = String(state.value).trim() || defaultProjectName)
        },
        // 省略若干配置
        {
          name: 'needsTests',
          type: () => (isFeatureFlagsUsed ? null : 'toggle'),
          message: 'Add Cypress for testing?',
          initial: false,
          active: 'Yes',
          inactive: 'No'
        }
      ],
      {
        onCancel: () => {
          throw new Error(red('✖') + ' Operation cancelled')
        }
      }
    ]
    )
  } catch (cancelled) {
    console.log(cancelled.message)
    // 退出当前进程。
    process.exit(1)
  }

4.4 初始化询问用户给到的参数,同时也会给到默认值

// `initial` won't take effect if the prompt type is null
  // so we still have to assign the default values here
  const {
    packageName = toValidPackageName(defaultProjectName),
    shouldOverwrite,
    needsJsx = argv.jsx,
    needsTypeScript = argv.typescript,
    needsRouter = argv.router,
    needsVuex = argv.vuex,
    needsTests = argv.tests
  } = result
  const root = path.join(cwd, targetDir)

  // 如果需要强制重写,清空文件夹

  if (shouldOverwrite) {
    emptyDir(root)
    // 如果不存在文件夹,则创建
  } else if (!fs.existsSync(root)) {
    fs.mkdirSync(root)
  }

  // 脚手架项目目录
  console.log(`\nScaffolding project in ${root}...`)

 // 生成 package.json 文件
  const pkg = { name: packageName, version: '0.0.0' }
  fs.writeFileSync(path.resolve(root, 'package.json'), JSON.stringify(pkg, null, 2))

4.5 根据模板文件生成初始化项目所需文件

// todo:
  // work around the esbuild issue that `import.meta.url` cannot be correctly transpiled
  // when bundling for node and the format is cjs
  // const templateRoot = new URL('./template', import.meta.url).pathname
  const templateRoot = path.resolve(__dirname, 'template')
  const render = function render(templateName) {
    const templateDir = path.resolve(templateRoot, templateName)
    renderTemplate(templateDir, root)
  }

  // Render base template
  render('base')

   // 添加配置
  // Add configs.
  if (needsJsx) {
    render('config/jsx')
  }
  if (needsRouter) {
    render('config/router')
  }
  if (needsVuex) {
    render('config/vuex')
  }
  if (needsTests) {
    render('config/cypress')
  }
  if (needsTypeScript) {
    render('config/typescript')
  }

4.6 渲染生成代码模板

// Render code template.
  // prettier-ignore
  const codeTemplate =
    (needsTypeScript ? 'typescript-' : '') +
    (needsRouter ? 'router' : 'default')
  render(`code/${codeTemplate}`)

  // Render entry file (main.js/ts).
  if (needsVuex && needsRouter) {
    render('entry/vuex-and-router')
  } else if (needsVuex) {
    render('entry/vuex')
  } else if (needsRouter) {
    render('entry/router')
  } else {
    render('entry/default')
  }

4.7 如果配置了需要 ts

重命名所有的 .js 文件改成 .ts。重命名 jsconfig.json 文件为 tsconfig.json 文件。

jsconfig.json[15] 是VSCode的配置文件,可用于配置跳转等。

index.html 文件里的 main.js 重命名为 main.ts

// Cleanup.

if (needsTypeScript) {
    // rename all `.js` files to `.ts`
    // rename jsconfig.json to tsconfig.json
    preOrderDirectoryTraverse(
      root,
      () => {},
      (filepath) => {
        if (filepath.endsWith('.js')) {
          fs.renameSync(filepath, filepath.replace(/\.js$/, '.ts'))
        } else if (path.basename(filepath) === 'jsconfig.json') {
          fs.renameSync(filepath, filepath.replace(/jsconfig\.json$/, 'tsconfig.json'))
        }
      }
    )

    // Rename entry in `index.html`
    const indexHtmlPath = path.resolve(root, 'index.html')
    const indexHtmlContent = fs.readFileSync(indexHtmlPath, 'utf8')
    fs.writeFileSync(indexHtmlPath, indexHtmlContent.replace('src/main.js', 'src/main.ts'))
  }

4.8 配置了不需要测试

因为所有的模板都有测试文件,所以不需要测试时,执行删除 cypress/__tests__/ 文件夹

if (!needsTests) {
    // All templates assumes the need of tests.
    // If the user doesn't need it:
    // rm -rf cypress **/__tests__/
    preOrderDirectoryTraverse(
      root,
      (dirpath) => {
        const dirname = path.basename(dirpath)

        if (dirname === 'cypress' || dirname === '__tests__') {
          emptyDir(dirpath)
          fs.rmdirSync(dirpath)
        }
      },
      () => {}
    )
  }

4.9 根据使用的 npm / yarn / pnpm 生成README.md 文件,给出运行项目的提示

// Instructions:
  // Supported package managers: pnpm > yarn > npm
  // Note: until <https://github.com/pnpm/pnpm/issues/3505> is resolved,
  // it is not possible to tell if the command is called by `pnpm init`.
  const packageManager = /pnpm/.test(process.env.npm_execpath)
    ? 'pnpm'
    : /yarn/.test(process.env.npm_execpath)
    ? 'yarn'
    : 'npm'

  // README generation
  fs.writeFileSync(
    path.resolve(root, 'README.md'),
    generateReadme({
      projectName: result.projectName || defaultProjectName,
      packageManager,
      needsTypeScript,
      needsTests
    })
  )

  console.log(`\nDone. Now run:\n`)
  if (root !== cwd) {
    console.log(`  ${bold(green(`cd ${path.relative(cwd, root)}`))}`)
  }
  console.log(`  ${bold(green(getCommand(packageManager, 'install')))}`)
  console.log(`  ${bold(green(getCommand(packageManager, 'dev')))}`)
  console.log()

5. npm run test => node test.js 测试

// create-vue/test.js
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'

import { spawnSync } from 'child_process'

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const playgroundDir = path.resolve(__dirname, './playground/')

for (const projectName of fs.readdirSync(playgroundDir)) {
  if (projectName.endsWith('with-tests')) {
    console.log(`Running unit tests in ${projectName}`)
    const unitTestResult = spawnSync('pnpm', ['test:unit:ci'], {
      cwd: path.resolve(playgroundDir, projectName),
      stdio: 'inherit',
      shell: true
    })
    if (unitTestResult.status !== 0) {
      throw new Error(`Unit tests failed in ${projectName}`)
    }

    console.log(`Running e2e tests in ${projectName}`)
    const e2eTestResult = spawnSync('pnpm', ['test:e2e:ci'], {
      cwd: path.resolve(playgroundDir, projectName),
      stdio: 'inherit',
      shell: true
    })
    if (e2eTestResult.status !== 0) {
      throw new Error(`E2E tests failed in ${projectName}`)
    }
  }
}

主要对生成快照时生成的在 playground 32个文件夹,进行如下测试。

pnpm test:unit:ci

pnpm test:e2e:ci

6. 总结

我们使用了快如闪电般的npm init vue@next,学习npx命令了。学会了其原理。

npm init vue@next => npx create-vue@next

快如闪电的原因在于依赖的很少。很多都是自己来实现。如:Vue-CLIvue create vue-project 命令是用官方的npm包validate-npm-package-name[16],删除文件夹一般都是使用 rimraf[17]。而 create-vue 是自己实现emptyDirisValidPackageName

非常建议读者朋友按照文中方法使用VSCode调试 create-vue 源码。源码中还有很多细节文中由于篇幅有限,未全面展开讲述。

学完本文,可以为自己或者公司创建类似初始化脚手架。

目前版本是3.0.0-beta.6。我们持续关注学习它。除了create-vue 之外,我们还可以看看create-vite[18]、create-umi[19] 的源码实现。

最后欢迎加我微信 ruochuan12源码共读 活动,大家一起学习源码,共同进步。

7. 参考资料

发现 create-vue 时打算写文章加入到源码共读比我先写完文章。

@upupming  vue-cli 将被 create-vue 替代?初始化基于 vite 的 vue3 项目为何如此简单?

参考资料

[1]

点击阅读原文查看更多

最近组建了一个湖南人的前端交流群,如果你是湖南人可以加我微信 ruochuan12 私信 湖南 拉你进群。


推荐阅读

1个月,200+人,一起读了4周源码
我历时3年才写了10余篇源码文章,但收获了100w+阅读

老姚浅谈:怎么学JavaScript?

我在阿里招前端,该怎么帮你(可进面试群)

48ea46ad379c287f6b6f7d3f2ead7785.gif

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列
从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结
同时,最近组织了源码共读活动

8b19b9b1a24f52305f09f5a006722c43.png

识别方二维码加我微信、拉你进源码共读

今日话题

略。欢迎分享、收藏、点赞、在看我的公众号文章~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Vue 团队公开快如闪电的全新脚手架工具,未来将替代 Vue-CLI,才300余行代码,学它!... 的相关文章

  • 多次训练brain.js?

    在第一次训练后 如何将新信息 仅新信息 而不是所有信息 因为这会花费太多性能 训练到我的用 Brain js 制作的神经网络 它有点粗糙 但您可以使用以下结构来实现 如果我们加入 2 个训练数据集 旧数据集与新数据集 然后重新训练keepN
  • 如何将jscrollpane添加到jframe?

    我有以下源代码 有人可以给我建议如何将 jscrollpane 添加到 jframe 上吗 我尝试了几次将其添加到 jframe 但没有任何进展 它甚至没有显示 public class Form3 JFrame jframe new JF
  • 如何在java Spring Boot中实现通用服务类?

    我有许多具有重复代码的服务 我想知道如何实现通用服务 以便我的所有服务都可以扩展它 服务接口示例 重复代码 Service public interface IUserService List
  • 为什么 MOVE CURSOR 在 OS X Mountain Lion 上不显示?

    我正在做一个项目 想看看 Swing 提供的每个光标是什么样子的 public class Test public static void main String args JFrame frame new JFrame frame set
  • 如何通过注解用try-catch包装方法?

    如果应该在方法调用中忽略异常 则可以编写以下内容 public void addEntryIfPresent String key Dto dto try Map
  • 从休眠乐观锁定异常中恢复

    我有一个这样的方法 Transactional propagation Propagation REQUIRES NEW public void doSomeWork Entity entity dao loadEntity do some
  • 使用 Javascript/Node.js 在代码内执行 mongoimport

    node js javascript 中是否有任何库可供个人使用mongoimport在代码中 据我了解 mongoimport 有点像 exe 您必须先执行它 然后才能使用其文本输入环境 是否可以在我的代码中执行 mongoimport
  • Eclipse - 安装新的 JRE (Java SE 8 1.8.0)

    我正在尝试安装 Java 8 到目前为止我所做的 安装最新版本的 Eclipse 下载并安装 Java SE 运行时环境 8http www oracle com technetwork java javase downloads jre8
  • 在 Java 中通过 XSLT 分解 XML

    我需要转换具有嵌套 分层 表单结构的大型 XML 文件
  • 如何从日期中删除毫秒、秒、分钟和小时[重复]

    这个问题在这里已经有答案了 我遇到了一个问题 我想比较两个日期 然而 我只想比较年 月 日 这就是我能想到的 private Date trim Date date Calendar calendar Calendar getInstanc
  • 如何通过 Android 按钮单击运行单独的应用程序

    我尝试在 Android 应用程序中添加两个按钮 以从单独的两个应用程序订单系统和库存系统中选择一个应用程序 如图所示 我已将这两个应用程序实现为两个单独的 Android 项目 当我尝试运行此应用程序时 它会出现直到正确选择窗口 但是当按
  • 在 Clojure 中解压缩 zlib 流

    我有一个二进制文件 其内容由zlib compress在Python上 有没有一种简单的方法可以在Clojure中打开和解压缩它 import zlib import json with open data json zlib wb as
  • 使用Java绘制维恩图

    我正在尝试根据给定的布尔方程绘制维恩图 例如 a AND b AND c我想在 Android 手机上执行此操作 因此我需要找到一种使用 Java 来执行此操作的方法 我找到了一个完美的小部件 它可以完成我在这方面寻找的一切布尔代数计算器
  • 我可以限制分布式应用程序发出的请求吗?

    我的应用程序发出 Web 服务请求 提供商处理的请求有最大速率 因此我需要限制它们 当应用程序在单个服务器上运行时 我曾经在应用程序级别执行此操作 一个对象跟踪到目前为止已发出的请求数量 并在当前请求超出允许的最大负载时等待 现在 我们正在
  • 使用 Java https 上传到 Imgur v3 错误

    我目前正在尝试使用他们当前的 API v3 上传到 imgur 但是我不断收到错误 错误 javax net ssl SSLException 证书中的主机名不匹配 api imgur com imgur com OR imgur com
  • Java 的 PriorityQueue 与最小堆有何不同?

    他们为什么命名PriorityQueue如果你不能插入优先级 它看起来与堆非常相似 有什么区别吗 如果没有区别那为什么叫它PriorityQueue而不是堆 默认的PriorityQueue是用Min Heap实现的 即栈顶元素是堆中最小的
  • 无论我将其添加到何处,Azure 应用程序服务(节点)CORS 源都无法工作

    Azure CORS 设置似乎根本不起作用 除非我指定 任何和所有请求都将返回 has been blocked by CORS policy Response to preflight request doesn t pass acces
  • 记录类名、方法名和行号的性能影响

    我正在我的 java 应用程序中实现日志记录 以便我可以调试应用程序投入生产后可能出现的潜在问题 考虑到在这种情况下 人们不会奢侈地使用 IDE 开发工具 以调试模式运行事物或单步执行完整代码 因此在每条消息中记录类名 方法名和行号将非常有
  • 使用 JFreeChart 为两个系列设置不同的 y 轴

    我正在使用 JFreeChart 使用折线图绘制两个数据系列 XYSeries 复杂的因素是 其中一个数据系列的 y 值通常远高于第二个数据系列的 y 值 假设第一个系列的 y 值约为数百万数量级 而第二个数据系列的 y 值约为数百万数量级
  • ArrayList.clear() 和 ArrayList.removeAll() 有什么区别?

    假如说arraylist定义为ArrayList

随机推荐

  • mysql hash分区要点

    mysql 有很多种表分区的方式 这里写一些笔者对于hash分区的感悟 如有错误 恳请读者斧正 mysql hash分区不用像其他的分区指定 当某一列值得情况为某某某的情况去到某一分区 比如list分区和range分区 hash直接只用指定
  • My eclipse 无法打开workspace解决方案

    今天用myeclipse的时候试图引用code comment style 在引用的过程中死掉了 就杀死进程 myeclipse提示crash 再打开次workspace 就一直处于 loading workbench 状态 打开其他wor
  • 进程和线程的区别

    进程 Process 和线程 Thread 是操作系统中的两个重要概念 它们是实现多任务并发执行的两种方式 它们有以下主要区别 1 定义和资源 进程 进程是正在运行的程序的实例 拥有独立的地址空间和资源 每个进程都有自己的代码 数据 堆栈
  • Windows11 拒绝访问压缩(zipped)文件夹

    最近windows10被自动升级到windows11 使用的一个工具zip压缩包突然就无法解压了 提示 拒绝访问压缩 zipped 文件夹 提取文件之前 必须更改这个压缩文件夹的权限 我的尝试 更改了这个压缩包文件的属性中的各个用户权限 增
  • 数字图像处理 基于python读取DICOM、NIfTI格式医学图像文件

    一 医学图像 医学图像标注最重要的进步之一是应用机器学习来评估图像 以实现更精确 更快 更准确的医学诊断 在应用机器学习 ML 人工智能 AI 或任何其他诊断算法之前 您需要知道注释软件可以处理两种最常见的医疗和保健图像文件格式 包括 DI
  • SpringBoot如何避免SQL注入漏洞呢?

    转自 SpringBoot如何避免SQL注入漏洞呢 下文笔者讲述SpringBoot避免SQL注入漏洞的方法分享 如下所示 SQL盲注 SQL注入简介 SQL注入的风险 数据库中的数据被任意查看 修改 删除 SQL注入的原因 未对用户输入进
  • mysql的驱动connect放在哪里_MySQL文档阅读笔记之JDBC驱动参数autoReconnect的副作用...

    MySQL的特性之一可高度定制化 相应的MySQL提供的JDBC驱动也提供了相当多的参数 老实说 第一次阅读文档时 真心晕 不过还是禁不住的赞叹 MySQL的JDBC驱动都有茫茫多的参数 果然有特点 这些参数中autoReconnect吸引
  • 无注册中心使用dubbo

    前言 熟悉dubbo的朋友都知道 dubbo可通过指定Url方式绕过注册中心直连指定的服务地址 所以想当然会想到那么可不可以不使用注册中心 本文就是SpringBoot整合Dubbo 无注册中心 的示例展示 提供者dubbo provide
  • Cobar使用文档(可用作MySQL大型集群解决方案)

    Cobar使用文档 可用作MySQL大型集群解决方案 2013 12 11 16 06 17236人阅读 评论 0 收藏 举报 分类 cobar 1 转 http blog csdn net shagoo article details 8
  • Python操作Excel插入删除行

    Python操作Excel插入删除行 1 前言 2 使用openpyxl 3 使用xlwings 3 1 删除行 range api EntireRow Delete 3 2 插入行 sheet api Rows row number In
  • 信息系统之网络安全方案 — “3保1评”

    信息系统之网络安全方案 3保1评 序 什么是 3评1保 一 网络安全等级保护 1 1 概念 1 2等保发展 1 3法律要求 1 4分级及工作流程 二 涉密信息系统分级保护 2 1概念 2 2法律要求 2 3分级及工作流程 三 关键信息基础设
  • unity3d-常用组件

    Component 学习阶段我会不断的更新新的内容 文章如有误请指正 如果觉得对你有用 请点赞收藏关注一波 谢谢支持 Rigidbody 变量 公共函数 消息 公共函数 2D 静态函数 2D 射线 RaycastHit 2D 1 变量 Ph
  • 51单片机控制数码管显示以及控制打断

    实践内容 1 利用单片机的P0口接数码管的字段脚 P1 0脚接共阴极 P3 2 P3 3引脚接独立按键产生外部中断信号 编写程序 当程序正常运行时数码管显示H字符 当外部中断0有中断请求信号时 数码管从0 9循环显示一次后回到正常状态 如果
  • ARP攻击后续

    查看ARP缓存表 我们先了解一下ARP缓存表的概念 络设备一般都有一个ARP缓存 ARP Cache ARP缓存用来存放IP地址和MAC地址的关联信息 在发送数据前 设备会先查找ARP缓存表 如果缓存表中存在对方设备的MAC地址 则直接采用
  • VS2013编译FFMPEG遇到的坑

    因为需要 用到老的FFMPEG库 但官方又没有编译好的LIB和DLL 只能下载源码自己编译了 但对LINUX环境不懂 只有在WINDOWS上配置环境编译 记录过程如下 1 下载FFMPEG源码 下载地址 http ffmpeg zerano
  • RV32I指令集

    RV32I是最基本的32位Base指令集 它支持32位寻址空间 支持字节地址访问 仅支持小端格式 little endian 高地址高位 低地址地位 寄存器也是32位整数寄存器 RV32I指令集的目的是尽量简化硬件的实施设计 所以它只有47
  • 蓝奏云访问修复(JavaScript 几个参数及命令讲解)

    每次都要更改蓝奏云分享链接中的 www lanzous com 为 ww lanzous com 麻烦 改 Hosts 有效果 但写个脚本不香么 蓝奏云访问 用到的命令和参数 window location href 当前页面的 URL 字
  • 解决粘包问题的三种方法

    方法一 定长数据流 服务器客户端提前协商 每个消息定长 不足的空白字符补足 方法二 特殊结束符 双方协商定义一个特殊的分隔符号 比如 等 只要没有发送分隔符就意味着一条数据没有结束 方法三 协议 相对最成熟额数据传递方式 由服务器开发者提供
  • http常见字段

    Host字段 客户端发送请求时 用来指定服务器域名 有了Host字段 就可以将请求发往同一台服务器上的不同网站 Content Length 字段 服务器在返回数据时 会有Content Length字段 表名本次回应的数据长度 Conne
  • Vue 团队公开快如闪电的全新脚手架工具,未来将替代 Vue-CLI,才300余行代码,学它!...

    1 前言 大家好 我是若川 欢迎关注我的公众号若川视野源码共读活动ruochuan12 想学源码 极力推荐之前我写的 学习源码整体架构系列 jQuery underscore lodash vuex sentry axios redux k