Project Icon

eslint-plugin-simple-import-sort

ESLint插件实现简单自动导入排序

eslint-plugin-simple-import-sort是一款轻量级ESLint插件,用于自动排序和修复导入语句。该插件支持TypeScript、Prettier和dprint,能处理注释及类型导入导出,并与eslint-plugin-import兼容。它简化了导入排序流程,无需额外工具,适合经常使用eslint --fix的开发者。

eslint-plugin-simple-import-sort

简单易用的自动修复导入排序。

  • ✅️ 通过 [eslint --fix][eslint-fix] 运行 – 无需新工具
  • ✅️ 也可以在可能的情况下排序导出
  • ✅️ 处理注释
  • ✅️ 处理类型导入/导出
  • ✅️ [TypeScript] 友好(通过 [@typescript-eslint/parser])
  • ✅️ [Prettier] 友好
  • ✅️ [dprint] 友好([需要配置][dprint-configuration])
  • ✅️ [eslint-plugin-import] 友好
  • ✅️ git diff 友好
  • ✅️ 100% 代码覆盖率
  • ✅️ 无依赖
  • ❌ [不支持 require][no-require]

这适用于经常使用 [eslint --fix][eslint-fix](自动修复)并想完全忘记导入排序的人!

示例

import React from "react";
import Button from "../Button";

import styles from "./styles.css";
import type { User } from "../../types";
import { getUser } from "../../api";

import PropTypes from "prop-types";
import classnames from "classnames";
import { truncate, formatNumber } from "../../utils";

⬇️

import classnames from "classnames";
import PropTypes from "prop-types";
import React from "react";

import { getUser } from "../../api";
import type { User } from "../../types";
import { formatNumber, truncate } from "../../utils";
import Button from "../Button";
import styles from "./styles.css";

更多示例

安装

npm install --save-dev eslint-plugin-simple-import-sort

ℹ️ 这是一个 ESLint 插件。👉 ESLint 入门指南

使用方法

  • eslintrc: 在 .eslintrc.* 文件的 "plugins" 数组中添加 "simple-import-sort",并添加用于排序导入和导出的规则。默认情况下,ESLint 不解析 import 语法 – "parserOptions" 是启用它的示例。

    {
      "plugins": ["simple-import-sort"],
      "rules": {
        "simple-import-sort/imports": "error",
        "simple-import-sort/exports": "error"
      },
      "parserOptions": {
        "sourceType": "module",
        "ecmaVersion": "latest"
      }
    }
    
  • [eslint.config.js (平铺配置)]: 导入 eslint-plugin-simple-import-sort,将其放入 plugins 对象中,并添加用于排序导入和导出的规则。使用平铺配置时,默认启用 import 语法。

    import simpleImportSort from "eslint-plugin-simple-import-sort";
    
    export default [
      {
        plugins: {
          "simple-import-sort": simpleImportSort,
        },
        rules: {
          "simple-import-sort/imports": "error",
          "simple-import-sort/exports": "error",
        },
      },
    ];
    

确保不要同时使用其他排序规则:

ℹ️ 注意:曾经有一个名为 "simple-import-sort/sort" 的规则。从 6.0.0 版本开始,它被称为 "simple-import-sort/imports"

配置示例

这个示例使用了 [eslint-plugin-import],这是可选的。

建议同时设置 [Prettier],以帮助格式化你的导入(以及所有其他代码)。

{
  "parserOptions": {
    "sourceType": "module",
    "ecmaVersion": "latest"
  },
  "plugins": ["simple-import-sort", "import"],
  "rules": {
    "simple-import-sort/imports": "error",
    "simple-import-sort/exports": "error",
    "import/first": "error",
    "import/newline-after-import": "error",
    "import/no-duplicates": "error"
  }
}
  • "sourceType": "module""ecmaVersion": "latest" 是必需的,这样 ESLint 就不会将 importexport 报告为语法错误。
  • 对所有文件启用 simple-import-sort/importssimple-import-sort/exports
  • import/first 确保所有导入都在文件顶部。(可自动修复)
  • import/newline-after-import 确保导入后有一个空行。(可自动修复)
  • import/no-duplicates 合并相同文件的导入语句。(大部分可自动修复)

不适合所有人

这个插件并不适合所有人。让我解释一下。

长期以来,这个插件没有任何选项,这有助于保持它的简单性。

虽然人工字母排序和注释处理似乎适用于很多人,但导入分组更加困难。项目之间的差异太大,无法有一个通用的分组方式。

我决定只提供这一个选项,不再增加其他。以下是一些你无法配置的内容:

  • 每个组内的排序。它就是这样。参见[排序]。
  • 副作用导入的排序(它们始终保持原始顺序)。

如果你想要更多选项,我建议使用 import/order 规则(来自 [eslint-plugin-import])。它有很多选项,维护者似乎有兴趣在合理的情况下扩展功能。

那么为什么这个插件存在呢?参见这个规则与 import/order 有何不同?

如果我们开始为这个插件添加更多选项,它就不再是 eslint-plugin-simple-import-sort 了。最终它将没有存在的理由 – 最好将精力用于为 import/order 贡献。

我为自己制作了这个插件。我在许多小项目中使用它,我喜欢它。如果你也喜欢 – 我很高兴听到!但并非每个人都会喜欢它。这没关系。

排序顺序

这个插件应该与自动修复一起使用,最好是直接在你的编辑器中通过 ESLint 扩展使用,或者使用 [eslint --fix][eslint-fix]。

本节是为了了解排序的工作原理,而不是如何手动修复错误。请使用自动修复!

总结: 先分组,然后按字母顺序排序。

分组

导入

首先,插件查找所有导入的。一个"块"是一系列导入语句,之间只有注释和空白。每个块单独排序。如果你想确保所有导入都在同一个块中,可以使用 import/first

然后,每个块被分组成几个部分,每个部分之间有一个空行。

  1. import "./setup": 副作用导入。(这些内部不排序。)
  2. import * as fs from "node:fs": 带有 node: 前缀的 Node.js 内置模块。
  3. import react from "react": 包(npm 包和不带 node: 的 Node.js 内置模块)。
  4. import a from "/a": 绝对导入和其他导入,如 Vue 风格的 @/foo
  5. import a from "./a": 相对导入。

注意:上述分组的定义非常宽松。更多信息请参见[自定义分组]。

导出

重新导出(带有 from 的导出)序列会被排序。其他类型的导出不会重新排序。

与导入不同,导出没有自动分组。相反,单独一行的注释会开始一个新组。这将分组留给你手动完成。

以下示例有 3 个组(一个包含 "x" 和 "y",一个包含 "a" 和 "b",一个包含 "./"):

export * from "x";
export * from "y";

// 这个注释开始一个新组。
/* 这个不会。 */ export * from "a"; // 这个也不会。
/* 这个
也不会 */ export * from "b";
/* 但这个会。 */
export * from "./";

每个组单独排序,组本身不排序 – 它们保持在你写它们的位置。

没有分组注释的话,上面的示例最终会变成这样:

export * from "./";
/* 这个不会。 */ export * from "a"; // 这个也不会。
/* 这个
也不会 */ export * from "b";
export * from "x";
export * from "y";

排序

在每个部分内,导入/导出按 from 字符串的字母顺序排序(另见"为什么按 from 排序?")。保持简单!看看这里的代码会有帮助:

const collator = new Intl.Collator("en", {
  sensitivity: "base",
  numeric: true,
});

function compare(a, b) {
  return collator.compare(a, b) || (a < b ? -1 : a > b ? 1 : 0);
}

换句话说,组内的导入/导出按字母顺序排序,不区分大小写,并像人类那样处理数字,在出现平局的情况下回退到传统的字符代码排序。更多信息请参阅Intl.Collator。注意:Intl.Collator以某种定义的顺序对标点符号进行排序。我不知道标点符号的排序顺序是什么,也不在乎。据我所知,标点符号没有有序的"字母表"。

对字母顺序规则有一个补充:目录结构。目录结构中较高层级文件的相对导入/导出排在较近层级之前——"../../utils"排在"../utils"之前,后者又排在"."之前。(简而言之,./排在任何其他(非空白、非控制)字符之前。".."和类似的排序如同"../,"(以避免"较短前缀排在前面"的排序概念)。)

如果对同一来源同时使用了import type和常规导入,类型导入排在前面。export type也是如此。(你可以将类型导入移到它们自己的组,如[自定义分组]中所述。)

示例

// 副作用导入。(这些内部不进行排序。)
import "./setup";
import "some-polyfill";
import "./global.css";

// 带有`node:`前缀的Node.js内置模块。
import * as fs from "node:fs";

// 包。
import type A from "an-npm-package";
import a from "an-npm-package";
import fs2 from "fs";
import b from "https://example.com/script.js";

// 绝对导入和其他导入。
import c from "/";
import d from "/home/user/foo";
import Error from "@/components/error.vue";

// 相对导入。
import e from "../..";
import type { B } from "../types";
import f from "../Utils"; // 不区分大小写。
import g from ".";
import h from "./constants";
import i from "./styles";

// 不同类型的导出:
export { a } from "../..";
export { b } from "/";
export { Error } from "@/components/error.vue";
export * from "an-npm-package";
export { readFile } from "fs";
export * as ns from "https://example.com/script.js";

// 这个注释分组了一些更多的导出:
export { e } from "../..";
export { f } from "../Utils";
export { g } from ".";
export { h } from "./constants";
export { i } from "./styles";

// 其他导出 – 插件不会触及这些,除了对大括号内的命名导出进行排序。
export var one = 1;
export let two = 2;
export const three = 3;
export function func() {}
export class Class {}
export type Type = string;
export { named, other as renamed };
export type { T, U as V };
export default whatever;

无论在哪个组中,导入的项目都按以下方式排序:

import {
  // 数字按其数值排序:
  img1,
  img2,
  img10,
  // 然后是其他所有内容,按字母顺序:
  k,
  L, // 不区分大小写。
  m as anotherName, // 按"外部接口"名称"m"排序,而不是"anotherName"。
  m as tie, // 但在出现平局时使用文件本地名称。
  // 类型的排序就像`type`关键字不存在一样。
  type x,
  y,
} from "./x";

即使对于没有from的导出,导出项也会被排序(尽管导出语句本身不会相对于其他导出进行排序):

export {
  k,
  L, // 不区分大小写。
  anotherName as m, // 按"外部接口"名称"m"排序,而不是"anotherName"。
  // tie as m, // 对于导出,不可能有平局 – 所有导出必须是唯一的。
  // 类型的排序就像`type`关键字不存在一样。
  type x,
  y,
};
export type { A, B, A as C };

乍一听,导入时a as ba排序,而导出时按b排序可能听起来有悖常理。这样做的原因是选择最"稳定"的名称。在import { a as b } from "./some-file.js"中,as b部分是为了避免文件中的名称冲突,而不必更改some-file.js。在export { b as a }中,b as部分是为了避免文件中的名称冲突,而不必更改文件的导出接口。

自定义分组

一个选项(参见[不适合所有人])称为groups,它对许多不同的用例都很有用。

groups是一个字符串数组的数组:

type Options = {
  groups: Array<Array<string>>;
};

每个字符串都是一个正则表达式(带有[u标志])。这些正则表达式决定哪些导入去往何处。(记得转义反斜杠 – 是"\\w",而不是"\w",例如。)

内部数组用一个换行符连接;外部数组用两个换行符连接 – 创建一个空行。这就是为什么有两级数组 – 它让你选择在哪里有空行。

以下是一些你可以做的事情:

  • 将非标准导入路径如src/Button@company/Button从(第三方)"包"组移出,放入它们自己的组。
  • react移到最前面。
  • 通过使用单个内部数组来避免导入之间的空行
  • 为样式导入创建单独的组。
  • 分开./../导入。
  • 完全不使用分组,只按字母顺序排序。

如果你在考虑自定义分组是因为想移动非标准导入路径,如src/Button(没有前导的./../)和@company/Button – 考虑使用不像npm包的名称,如@/Button~company/Button。这样你就不需要自定义分组,而且作为额外好处,对其他在代码库上工作的人来说可能会不那么混淮。

如果你有非常复杂的要求,请参见issue #31获取一些提示。

注意:对于导出,分组是通过注释手动完成的 – 参见[导出]。

每个import都会根据from字符串与所有正则表达式进行匹配。导入最终会出现在匹配最长的正则表达式处。在平局的情况下,第一个匹配的正则表达式胜出。

如果一个导入最终出现在错误的位置 – 尝试让所需的正则表达式匹配from字符串的更多部分,或使用否定前瞻((?!x))来排除其他组中的内容。

不匹配任何正则表达式的导入会被放在最后。

副作用导入的from字符串前面会添加\u0000(以\u0000开头)。你可以用"^\\u0000"来匹配它们。

类型导入的from字符串后面会添加\u0000(以\u0000结尾)。你可以用"\\u0000$"来匹配它们 – 但你可能需要更多内容来避免它们也被其他正则表达式匹配。

匹配同一正则表达式的所有导入会按照[排序顺序]中提到的方式内部排序。

这是groups选项的默认值:

[
  // 副作用导入。
  ["^\\u0000"],
  // 带有`node:`前缀的Node.js内置模块。
  ["^node:"],
  // 包。
  // 以字母(或数字或下划线)开头的内容,或者`@`后跟一个字母。
  ["^@?\\w"],
  // 绝对导入和其他导入,如Vue风格的`@/foo`。
  // 任何未在其他组中匹配的内容。
  ["^"],
  // 相对导入。
  // 任何以点开头的内容。
  ["^\\."],
];

细心的读者可能会注意到,上述正则表达式匹配的内容比它们的注释所说的要多。例如,"@config""_internal"被匹配为包,但它们都不是有效的npm包名。".foo"被匹配为相对导入,但".foo"到底是什么意思?不过,使用更具体的规则并没有太多好处。所以保持简单!

参见[示例]以获取灵感。

注释和空白处理

当通过排序移动导入/导出时,它们的注释也会随之移动。注释可以放在导入/导出的上方(除了第一个 – 稍后会详细说明),或者在其行的开头或结尾。

示例:

// 导入块之前的注释
/* c1 */ import c from "c"; // c2
// b1
import b from "b"; // b2
// a1

/* a2
 */ import a /* a3 */ from "a"; /* a4 */ /* 非a
*/ // 导入块之后的注释

⬇️

// 导入块之前的注释
// a1
/* a2
 */ import a /* a3 */ from "a"; /* a4 */ 
// b1
import b from "b"; // b2
/* c1 */ import c from "c"; // c2
/* 非a
*/ // 导入块之后的注释

现在比较这两个例子:

// @flow
import b from "b";
// a
import a from "a";
// eslint-disable-next-line import/no-extraneous-dependencies
import b from "b";
// a
import a from "a";

// @flow 注释应该位于文件顶部(它为该文件启用 Flow 类型检查),与 "b" 导入无关。另一方面,// eslint-disable-next-line 注释却与 "b" 导入相关。即使是文档注释也可能是针对整个文件或第一个导入。因此,这个插件无法确定是否应该将注释移到第一个导入之上(但它知道 //a 注释属于 "a" 导入)。

基于这个原因,导入/导出块上下的注释永远不会被移动。如有需要,你需要自己手动移动。

围绕导入/导出项的注释遵循类似的规则 - 它们可以放在项目上方,或者在其行的开头或结尾。第一个项目或换行符之前的注释保留在开头,最后一个项目之后的注释保留在结尾。

import { // 开头的注释
  /* c1 */ c /* c2 */, // c3
  // b1

  b as /* b2 */ renamed
  , /* b3 */ /* a1
  */ a /* not-a
  */ // 结尾的注释
} from "wherever";
import {
  e,
  d, /* d */ /* not-d
  */ // 尾随逗号后的结尾注释
} from "wherever2";
import {/* 开头的注释 */ g, /* g */ f /* f */} from "wherever3";

⬇️

import { // 开头的注释
/* a1
  */ a, 
  // b1
  b as /* b2 */ renamed
  , /* b3 */ 
  /* c1 */ c /* c2 */// c3
/* not-a
  */ // 结尾的注释
} from "wherever";
import {
  d, /* d */   e,
/* not-d
  */ // 尾随逗号后的结尾注释
} from "wherever2";
import {/* 开头的注释 */ f, /* f */g/* g */ } from "wherever3";

如果你对奇怪的空白感到疑惑 - 请参阅 "排序自动修复导致了一些奇怪的空白!"

说到空白 - 空行怎么处理?就像注释一样,很难知道排序后空行应该放在哪里。这个插件采用了一种简单的方法 - 导入/导出块中的所有空行都被移除,除了 /**/ 注释中的空行和在 [排序顺序] 中提到的组之间添加的空行。(注意:对于导出,组之间的空行完全由你决定 - 如果你在分组注释周围有空行,它们会被保留。)

(由于空行被移除,你可能会遇到与 lines-around-commentpadding-line-between-statements 规则略有不兼容的情况 - 我自己不使用这些规则,但我认为应该有解决方法。)

最后一条空白规则是,这个插件每行只放一个导入/导出。我从未见过有意将多个导入/导出放在同一行的真实项目。

常见问题

它支持 require 吗?

不支持。这是有意为之,以保持简单。对于 require 的排序,请使用其他排序规则,比如 import/order。或者考虑将使用 require 的代码迁移到 import。现在 import 已经得到很好的支持。

为什么按 from 排序?

一些其他的导入排序规则是根据 import 后的第一个名称排序,而不是 from 后的字符串。本插件有意按 from 字符串排序,以便于 git diff

看看这个例子:

import { productType } from "./constants";
import { truncate } from "./utils";

现在假设你还需要 arraySplit 工具:

import { productType } from "./constants";
import { arraySplit, truncate } from "./utils";

如果按 import 后的第一个名称排序(在这种情况下是 "productType" 和 "arraySplit"),这两个导入现在会交换顺序:

import { arraySplit, truncate } from "./utils";
import { productType } from "./constants";

另一方面,如果按 from 字符串排序(就像本插件所做的那样),导入会保持相同的顺序。这可以防止导入在你添加和删除内容时跳来跳去,保持你的 git 历史清晰,并减少合并冲突的风险。

排序导入/导出安全吗?

大部分情况下是安全的。

在 JavaScript 中,导入和重新导出可能会有副作用,因此改变它们的顺序可能会改变这些副作用执行的顺序。最佳实践是要么导入一个模块以获得其副作用,要么导入它导出的内容(并且绝不依赖重新导出的副作用)。

// 运行副作用的 `import`:
import "some-polyfill";

// 获取 `someUtil` 的 `import`:
import { someUtil } from "some-library";

仅用于副作用的导入会保持输入顺序。这些不会被排序:

import "b";
import "a";

既导出内容又运行副作用的导入很少见。如果你遇到这种情况 - 试着修复它,因为它会让所有使用这段代码的人感到困惑。如果无法修复,可以**忽略(部分)排序。**

另一个小问题是你有时需要手动移动注释 - 请参阅 注释和空白处理

为了完整起见,对导入的导入/导出项进行排序始终是安全的:

import { c, b, a } from "wherever";
// 等同于:
import { a, b, c } from "wherever";

注意:import {} from "wherever" 不被视为副作用导入。

最后,关于导出还有一点需要知道。考虑这种情况:

one.js:

export const title = "One";
export const one = 1;

two.js:

export const title = "Two";
export const two = 2;

reexport.js:

export * from "./one.js";
export * from "./two.js";

main.js:

import * as reexport from "./rexport.js";
console.log(reexport);

如果你运行 main.js 会发生什么?在 Node.js 和浏览器中,结果是:

{
  one: 1,
  two: 2,
}

注意 title 甚至不在对象中!这对排序来说是好事,因为这意味着重新排序 reexport.js 中的两个 export * from 导出是安全的 - 并不是最后一个导入"胜出",你也不会因为排序意外改变 title 的值。

然而,根据你使用的打包工具,这可能仍然会导致问题。以下是一些打包工具在编写时处理重复名称 title 的方式:

  • ✅ Webpack:编译时错误 - 安全。
  • ✅ Parcel:运行时错误 - 安全。
  • ⚠️ Rollup:编译时警告,但使用它们中的第一个,所以可能不安全。不过,可以将 Rollup 配置为将警告视为错误。
  • ✅ TypeScript:编译时错误 - 安全。

排序自动修复导致了一些奇怪的空白!

你可能会遇到一些奇怪的间距,例如逗号后缺少空格:

import {bar, baz,foo} from "example";

排序是这个插件中简单的部分。处理空白和注释是困难的部分。自动修复有时可能会在导入/导出周围产生一些奇怪的间距。我建议使用 [Prettier] 或启用其他可自动修复的 ESLint 空白规则,而不是手动修复这些空格。更多信息请参见 [示例]。

空白可能会变得奇怪的原因是,这个插件重用并移动已存在的空白,而不是删除和添加新的空白。这是为了与其他处理空白的 ESLint 规则保持兼容。

我可以在不使用自动修复的情况下使用这个吗?

不太可能。这个规则的错误消息就是 "运行自动修复来排序这些导入!"为什么?为了积极鼓励你使用 [eslint --fix][eslint-fix](自动修复),而不是浪费时间手动做计算机能更好完成的事情。我见过有人痛苦地一个个修复其他规则产生的晦涩(且烦人的!)排序错误,却没意识到这些错误可以被自动修复。最后,不试图制作更详细的消息使得这个插件的代码更容易处理。

如何为这个规则使用 eslint-ignore?

寻找这个规则的 /* eslint-disable */?请阅读所有关于**忽略(部分)排序的内容。**

这个规则与 import/order 有何不同?

import/order 规则以前不支持字母顺序排序,但现在支持了。那么 eslint-plugin-simple-import-sort 还能带来什么呢?

一些其他区别:

  • 本插件为每组导入/导出提供一个错误,而 import/order 可能会提供多个(详见我可以在不使用自动修复的情况下使用吗?)。换句话说,本插件在编辑器中显示的下划线更多,而 import/order 在错误数量上更多。
  • 本插件有一个单一(但非常强大)的选项,由一组正则表达式组成,而 import/order 有多个不同的选项。目前还不清楚哪个更容易配置。但 eslint-plugin-simple-import-sort 尝试开箱即用地实现最大功能。

如何将此插件与 dprint 一起使用?

[dprint] 也会对导入和导出进行排序,但不会对它们进行分组。相反,它会保留你自己的分组方式。

首先要问自己的是 dprint 是否足够好。如果是,那你就少了一个需要担心的工具!

但是,如果你想强制分组,你仍然可以使用 eslint-plugin-simple-import-sort。然而,这两者在某些排序边缘情况下可能会略有分歧。因此,最好在你的 dprint 配置文件中关闭排序:

{
  "typescript": {
    "module.sortImportDeclarations": "maintain"
  }
}

来源:https://dprint.dev/plugins/typescript/config/

如何移除导入之间的所有空行?

使用[自定义分组],将 groups 选项设置为只有一个内部数组。

例如,这是默认值但改为单个内部数组:

[["^\\u0000", "^node:", "^@?\\w", "^", "^\\."]];

(默认情况下,每个字符串都在自己的数组中(总共 5 个内部数组)– 这会在每个之间造成一个空行。)

许可证

MIT

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号