[Vite]vite-plugin-react和vite-plugin-react-swc插件原理了解

[Vite]vite-plugin-react和vite-plugin-react-swc插件原理了解

共同的作用

  1. JSX 支持:插件为 React 应用程序中的 JSX 语法提供支持,确保它可以被正确地转换为 JavaScript。
  2. Fast Refresh:提供热更新功能,当应用程序在开发服务器上运行时,可以快速地看到更改的效果,而不需要手动刷新页面。
  3. 装饰器支持:如果项目中使用了 TypeScript 装饰器,插件会正确处理它们。
  4. Source Maps:生成源代码映射,以便于在浏览器中调试源代码。
  5. Virtual DOM 的导入:确保 React 和 ReactDOM 的虚拟 DOM 导入被正确处理。
  6. 开发模式与生产模式的区分:在开发模式下,插件会提供更多的辅助功能,如 React 快速刷新;而在生产模式下,它会专注于代码的最小化和优化。
  7. ESLint 集成:可选地集成 ESLint,以在开发过程中提供代码质量和一致性的检查。
  8. 配置 Rollup:在构建过程中,插件可能会配置 Rollup 以适应 React 应用程序的特定需求。
  9. 兼容性:确保 React 应用程序可以在目标浏览器中运行,即使这些浏览器不支持最新的 JavaScript 特性。
  10. 自定义配置:允许用户通过 Vite 配置文件传递自定义选项给插件,例如指定 JSX 工厂函数或模式等。

vite-plugin-react

源码地址

https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/src/index.ts

逻辑解读

  1. 类型导入:代码开始部分导入了 TypeScript 类型,用于确保插件的类型正确性。
  2. 依赖懒加载loadBabel 函数用于按需加载 Babel,因为 Babel 只在开发模式下或当特定的插件被使用时才需要。
  3. 配置选项Options 接口定义了插件的配置选项,允许用户自定义包括 includeexcludejsxImportSourcejsxRuntime 等。
  4. 插件数组导出viteReact 函数返回一个插件数组,这些插件在 Vite 构建过程中执行不同的任务。
  5. 创建 Babel 插件配置viteBabel 插件对象配置了如何使用 Babel 来转换 React 代码,包括 JSX 支持和快速刷新。
  6. React 快速刷新viteReactRefresh 插件对象处理与 React 快速刷新相关的逻辑,包括在 index.html 中注入必要的脚本。
  7. 构建配置:在 config 函数中,插件可以修改 Vite 配置,例如设置 esbuild 选项或 optimizeDeps
  8. 配置解析configResolved 函数在 Vite 配置解析完成后调用,用于确定是否处于生产模式、项目根路径等。
  9. 转换函数transform 函数是 Vite 插件中的核心,用于实际的代码转换工作。它使用 Babel 来转换 JSX 语法,并在开发模式下添加 React 快速刷新的包装器。
  10. 快速刷新逻辑:根据配置和代码内容,插件决定是否需要对代码进行快速刷新包装。
  11. Babel 插件加载loadPlugin 函数用于加载 Babel 插件,确保插件的异步加载。
  12. Babel 选项创建createBabelOptions 函数用于创建 Babel 的选项对象,它可以从用户配置或默认值中初始化。
  13. 编译器检测hasCompilerhasCompilerWithDefaultRuntime 函数用于检测 Babel 插件列表中是否包含特定的编译器插件。
  14. 构建时警告处理silenceUseClientWarning 函数用于抑制 Rollup 的某些警告。
  15. 静态资源服务resolveIdload 函数用于处理静态资源的请求,例如 React 快速刷新运行时脚本。
  16. 转换 HTMLtransformIndexHtml 函数用于修改 index.html,注入快速刷新的脚本。
  17. 插件 APIViteReactPluginApi 类型定义了插件可以提供的 API,允许其他插件通过 reactBabel 钩子来修改 Babel 配置。
  18. 默认导出:最后,viteReact 函数作为默认导出,使其可以在 Vite 配置中使用。

总结来说,@vitejs/plugin-react 插件的主要功能是为 React 应用程序提供 Vite 构建和开发服务器的集成支持。它包括 JSX 语法的转换、React 组件的快速刷新(热更新)、以及对 React 运行时的配置。通过插件的配置选项,用户可以根据项目需求定制化插件的行为。

// eslint-disable-next-line import/no-duplicates
import type * as babelCore from '@babel/core'
// eslint-disable-next-line import/no-duplicates
import type { ParserOptions, TransformOptions } from '@babel/core'
import { createFilter } from 'vite'
import type {BuildOptions,Plugin,PluginOption,ResolvedConfig,UserConfig,
} from 'vite'
import {addClassComponentRefreshWrapper,addRefreshWrapper,preambleCode,runtimeCode,runtimePublicPath,
} from './fast-refresh'// lazy load babel since it's not used during build if plugins are not used
let babel: typeof babelCore | undefined
async function loadBabel() {if (!babel) {babel = await import('@babel/core')}return babel
}export interface Options {include?: string | RegExp | Array<string | RegExp>exclude?: string | RegExp | Array<string | RegExp>/*** Control where the JSX factory is imported from.* https://esbuild.github.io/api/#jsx-import-source* @default 'react'*/jsxImportSource?: string/*** Note: Skipping React import with classic runtime is not supported from v4* @default "automatic"*/jsxRuntime?: 'classic' | 'automatic'/*** Babel configuration applied in both dev and prod.*/babel?:| BabelOptions| ((id: string, options: { ssr?: boolean }) => BabelOptions)
}export type BabelOptions = Omit<TransformOptions,| 'ast'| 'filename'| 'root'| 'sourceFileName'| 'sourceMaps'| 'inputSourceMap'
>/*** The object type used by the `options` passed to plugins with* an `api.reactBabel` method.*/
export interface ReactBabelOptions extends BabelOptions {plugins: Extract<BabelOptions['plugins'], any[]>presets: Extract<BabelOptions['presets'], any[]>overrides: Extract<BabelOptions['overrides'], any[]>parserOpts: ParserOptions & {plugins: Extract<ParserOptions['plugins'], any[]>}
}type ReactBabelHook = (babelConfig: ReactBabelOptions,context: ReactBabelHookContext,config: ResolvedConfig,
) => voidtype ReactBabelHookContext = { ssr: boolean; id: string }export type ViteReactPluginApi = {/*** Manipulate the Babel options of `@vitejs/plugin-react`*/reactBabel?: ReactBabelHook
}const reactCompRE = /extends\s+(?:React\.)?(?:Pure)?Component/
const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/
const defaultIncludeRE = /\.[tj]sx?$/
const tsRE = /\.tsx?$/export default function viteReact(opts: Options = {}): PluginOption[] {// Provide default values for Rollup compat.let devBase = '/'const filter = createFilter(opts.include ?? defaultIncludeRE, opts.exclude)const jsxImportSource = opts.jsxImportSource ?? 'react'const jsxImportRuntime = `${jsxImportSource}/jsx-runtime`const jsxImportDevRuntime = `${jsxImportSource}/jsx-dev-runtime`let isProduction = truelet projectRoot = process.cwd()let skipFastRefresh = falselet runPluginOverrides:| ((options: ReactBabelOptions, context: ReactBabelHookContext) => void)| undefinedlet staticBabelOptions: ReactBabelOptions | undefined// Support patterns like:// - import * as React from 'react';// - import React from 'react';// - import React, {useEffect} from 'react';const importReactRE = /\bimport\s+(?:\*\s+as\s+)?React\b/const viteBabel: Plugin = {name: 'vite:react-babel',enforce: 'pre',config() {if (opts.jsxRuntime === 'classic') {return {esbuild: {jsx: 'transform',},}} else {return {esbuild: {jsx: 'automatic',jsxImportSource: opts.jsxImportSource,},optimizeDeps: { esbuildOptions: { jsx: 'automatic' } },}}},configResolved(config) {devBase = config.baseprojectRoot = config.rootisProduction = config.isProductionskipFastRefresh =isProduction ||config.command === 'build' ||config.server.hmr === falseif ('jsxPure' in opts) {config.logger.warnOnce('[@vitejs/plugin-react] jsxPure was removed. You can configure esbuild.jsxSideEffects directly.',)}const hooks: ReactBabelHook[] = config.plugins.map((plugin) => plugin.api?.reactBabel).filter(defined)if (hooks.length > 0) {runPluginOverrides = (babelOptions, context) => {hooks.forEach((hook) => hook(babelOptions, context, config))}} else if (typeof opts.babel !== 'function') {// Because hooks and the callback option can mutate the Babel options// we only create static option in this case and re-create them// each time otherwisestaticBabelOptions = createBabelOptions(opts.babel)}},async transform(code, id, options) {if (id.includes('/node_modules/')) returnconst [filepath] = id.split('?')if (!filter(filepath)) returnconst ssr = options?.ssr === trueconst babelOptions = (() => {if (staticBabelOptions) return staticBabelOptionsconst newBabelOptions = createBabelOptions(typeof opts.babel === 'function'? opts.babel(id, { ssr }): opts.babel,)runPluginOverrides?.(newBabelOptions, { id, ssr })return newBabelOptions})()const plugins = [...babelOptions.plugins]const isJSX = filepath.endsWith('x')const useFastRefresh =!skipFastRefresh &&!ssr &&(isJSX ||(opts.jsxRuntime === 'classic'? importReactRE.test(code): code.includes(jsxImportDevRuntime) ||code.includes(jsxImportRuntime)))if (useFastRefresh) {plugins.push([await loadPlugin('react-refresh/babel'),{ skipEnvCheck: true },])}if (opts.jsxRuntime === 'classic' && isJSX) {if (!isProduction) {// These development plugins are only needed for the classic runtime.plugins.push(await loadPlugin('@babel/plugin-transform-react-jsx-self'),await loadPlugin('@babel/plugin-transform-react-jsx-source'),)}}// Avoid parsing if no special transformation is neededif (!plugins.length &&!babelOptions.presets.length &&!babelOptions.configFile &&!babelOptions.babelrc) {return}const parserPlugins = [...babelOptions.parserOpts.plugins]if (!filepath.endsWith('.ts')) {parserPlugins.push('jsx')}if (tsRE.test(filepath)) {parserPlugins.push('typescript')}const babel = await loadBabel()const result = await babel.transformAsync(code, {...babelOptions,root: projectRoot,filename: id,sourceFileName: filepath,// Required for esbuild.jsxDev to provide correct line numbers// This crates issues the react compiler because the re-order is too important// People should use @babel/plugin-transform-react-jsx-development to get back good line numbersretainLines: hasCompiler(plugins)? false: !isProduction && isJSX && opts.jsxRuntime !== 'classic',parserOpts: {...babelOptions.parserOpts,sourceType: 'module',allowAwaitOutsideFunction: true,plugins: parserPlugins,},generatorOpts: {...babelOptions.generatorOpts,decoratorsBeforeExport: true,},plugins,sourceMaps: true,})if (result) {let code = result.code!if (useFastRefresh) {if (refreshContentRE.test(code)) {code = addRefreshWrapper(code, id)} else if (reactCompRE.test(code)) {code = addClassComponentRefreshWrapper(code, id)}}return { code, map: result.map }}},}// We can't add `react-dom` because the dependency is `react-dom/client`// for React 18 while it's `react-dom` for React 17. We'd need to detect// what React version the user has installed.const dependencies = ['react', jsxImportDevRuntime, jsxImportRuntime]const staticBabelPlugins =typeof opts.babel === 'object' ? opts.babel?.plugins ?? [] : []if (hasCompilerWithDefaultRuntime(staticBabelPlugins)) {dependencies.push('react/compiler-runtime')}const viteReactRefresh: Plugin = {name: 'vite:react-refresh',enforce: 'pre',config: (userConfig) => ({build: silenceUseClientWarning(userConfig),optimizeDeps: {include: dependencies,},resolve: {dedupe: ['react', 'react-dom'],},}),resolveId(id) {if (id === runtimePublicPath) {return id}},load(id) {if (id === runtimePublicPath) {return runtimeCode}},transformIndexHtml() {if (!skipFastRefresh)return [{tag: 'script',attrs: { type: 'module' },children: preambleCode.replace(`__BASE__`, devBase),},]},}return [viteBabel, viteReactRefresh]
}viteReact.preambleCode = preambleCodeconst silenceUseClientWarning = (userConfig: UserConfig): BuildOptions => ({rollupOptions: {onwarn(warning, defaultHandler) {if (warning.code === 'MODULE_LEVEL_DIRECTIVE' &&warning.message.includes('use client')) {return}if (userConfig.build?.rollupOptions?.onwarn) {userConfig.build.rollupOptions.onwarn(warning, defaultHandler)} else {defaultHandler(warning)}},},
})const loadedPlugin = new Map<string, any>()
function loadPlugin(path: string): any {const cached = loadedPlugin.get(path)if (cached) return cachedconst promise = import(path).then((module) => {const value = module.default || moduleloadedPlugin.set(path, value)return value})loadedPlugin.set(path, promise)return promise
}function createBabelOptions(rawOptions?: BabelOptions) {const babelOptions = {babelrc: false,configFile: false,...rawOptions,} as ReactBabelOptionsbabelOptions.plugins ||= []babelOptions.presets ||= []babelOptions.overrides ||= []babelOptions.parserOpts ||= {} as anybabelOptions.parserOpts.plugins ||= []return babelOptions
}function defined<T>(value: T | undefined): value is T {return value !== undefined
}function hasCompiler(plugins: ReactBabelOptions['plugins']) {return plugins.some((p) =>p === 'babel-plugin-react-compiler' ||(Array.isArray(p) && p[0] === 'babel-plugin-react-compiler'),)
}// https://gist.github.com/poteto/37c076bf112a07ba39d0e5f0645fec43
function hasCompilerWithDefaultRuntime(plugins: ReactBabelOptions['plugins']) {return plugins.some((p) =>p === 'babel-plugin-react-compiler' ||(Array.isArray(p) &&p[0] === 'babel-plugin-react-compiler' &&p[1]?.runtimeModule === undefined),)
}

vite-plugin-react-swc

官方地址:vite-plugin-react-swc

核心:它使用SWC来替代Babel进行打包,速度快了很多。

源码地址

https://github.com/vitejs/vite-plugin-react-swc/blob/main/src/index.ts

逻辑解读

  1. 导入依赖:代码开始部分导入了 Node.js 的内置模块和第三方库,如 fspathurl 等,以及 @swc/core 和 Vite 的类型定义。
  2. 定义插件选项Options 类型定义了插件的配置选项,包括 jsxImportSourcetsDecoratorspluginsdevTargetparserConfig
  3. react 函数:这是一个工厂函数,用于创建 Vite 插件数组。它接受用户配置并返回配置好的插件对象。
  4. 处理 HMR:代码检查了服务器是否启用了热模块替换(HMR),如果没有启用,则设置 hmrDisabled 标志。
  5. 创建插件对象
    • 对象 vite:react-swc:resolve-runtime 用于解析 React 刷新运行时的路径,并提供相应的代码。
    • 对象 vite:react-swc 包含了多个属性和方法,用于处理开发服务器上的特定行为,如 configconfigResolvedtransformIndexHtmltransform
  6. React 快速刷新:在 transform 方法中,插件会检查代码是否包含 React 组件或刷新相关的代码。如果是,它将修改代码以支持 React 快速刷新。
  7. Source Map 处理:对于支持快速刷新的代码,插件会修改 Source Map,以确保源代码映射正确。
  8. 构建时的配置:当插件应用于构建时,它会配置 SWC 以使用特定的目标和插件选项进行代码转换。
  9. transformWithOptions 函数:这是一个异步函数,用于执行实际的代码转换。它接受文件 ID、代码、目标、选项和 React 配置,然后调用 SWC 的 transform 方法。
  10. silenceUseClientWarning 函数:这个函数用于抑制 Rollup 的警告,特别是与 "use client" 相关的警告。
  11. 导出默认:最后,react 函数作为默认导出,使其可以在 Vite 配置中使用。
import { readFileSync } from "fs";
import { dirname, join } from "path";
import { fileURLToPath } from "url";
import { SourceMapPayload } from "module";
import {Output,ParserConfig,ReactConfig,JscTarget,transform,
} from "@swc/core";
import { PluginOption, UserConfig, BuildOptions } from "vite";
import { createRequire } from "module";const runtimePublicPath = "/@react-refresh";const preambleCode = `import { injectIntoGlobalHook } from "__PATH__";
injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type;`;const _dirname =typeof __dirname !== "undefined"? __dirname: dirname(fileURLToPath(import.meta.url));
const resolve = createRequire(typeof __filename !== "undefined" ? __filename : import.meta.url,
).resolve;
const reactCompRE = /extends\s+(?:React\.)?(?:Pure)?Component/;
const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;type Options = {/*** Control where the JSX factory is imported from.* @default "react"*/jsxImportSource?: string;/*** Enable TypeScript decorators. Requires experimentalDecorators in tsconfig.* @default false*/tsDecorators?: boolean;/*** Use SWC plugins. Enable SWC at build time.* @default undefined*/plugins?: [string, Record<string, any>][];/*** Set the target for SWC in dev. This can avoid to down-transpile private class method for example.* For production target, see https://vitejs.dev/config/build-options.html#build-target* @default "es2020"*/devTarget?: JscTarget;/*** Override the default include list (.ts, .tsx, .mts, .jsx, .mdx).* This requires to redefine the config for any file you want to be included.* If you want to trigger fast refresh on compiled JS, use `jsx: true`.* Exclusion of node_modules should be handled by the function if needed.*/parserConfig?: (id: string) => ParserConfig | undefined;
};const isWebContainer = globalThis.process?.versions?.webcontainer;const react = (_options?: Options): PluginOption[] => {let hmrDisabled = false;const options = {jsxImportSource: _options?.jsxImportSource ?? "react",tsDecorators: _options?.tsDecorators,plugins: _options?.plugins? _options?.plugins.map((el): typeof el => [resolve(el[0]), el[1]]): undefined,devTarget: _options?.devTarget ?? "es2020",parserConfig: _options?.parserConfig,};return [{name: "vite:react-swc:resolve-runtime",apply: "serve",enforce: "pre", // Run before Vite default resolve to avoid syscallsresolveId: (id) => (id === runtimePublicPath ? id : undefined),load: (id) =>id === runtimePublicPath? readFileSync(join(_dirname, "refresh-runtime.js"), "utf-8"): undefined,},{name: "vite:react-swc",apply: "serve",config: () => ({esbuild: false,optimizeDeps: {include: [`${options.jsxImportSource}/jsx-dev-runtime`],esbuildOptions: { jsx: "automatic" },},}),configResolved(config) {if (config.server.hmr === false) hmrDisabled = true;const mdxIndex = config.plugins.findIndex((p) => p.name === "@mdx-js/rollup",);if (mdxIndex !== -1 &&mdxIndex >config.plugins.findIndex((p) => p.name === "vite:react-swc")) {throw new Error("[vite:react-swc] The MDX plugin should be placed before this plugin",);}if (isWebContainer) {config.logger.warn("[vite:react-swc] SWC is currently not supported in WebContainers. You can use the default React plugin instead.",);}},transformIndexHtml: (_, config) => [{tag: "script",attrs: { type: "module" },children: preambleCode.replace("__PATH__",config.server!.config.base + runtimePublicPath.slice(1),),},],async transform(code, _id, transformOptions) {const id = _id.split("?")[0];const refresh = !transformOptions?.ssr && !hmrDisabled;const result = await transformWithOptions(id,code,options.devTarget,options,{refresh,development: true,runtime: "automatic",importSource: options.jsxImportSource,},);if (!result) return;if (!refresh) return result;const hasRefresh = refreshContentRE.test(result.code);if (!hasRefresh && !reactCompRE.test(result.code)) return result;const sourceMap: SourceMapPayload = JSON.parse(result.map!);sourceMap.mappings = ";;" + sourceMap.mappings;result.code = `import * as RefreshRuntime from "${runtimePublicPath}";${result.code}`;if (hasRefresh) {sourceMap.mappings = ";;;;;;" + sourceMap.mappings;result.code = `if (!window.$RefreshReg$) throw new Error("React refresh preamble was not loaded. Something is wrong.");
const prevRefreshReg = window.$RefreshReg$;
const prevRefreshSig = window.$RefreshSig$;
window.$RefreshReg$ = RefreshRuntime.getRefreshReg("${id}");
window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;${result.code}window.$RefreshReg$ = prevRefreshReg;
window.$RefreshSig$ = prevRefreshSig;
`;}result.code += `
RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {RefreshRuntime.registerExportsForReactRefresh("${id}", currentExports);import.meta.hot.accept((nextExports) => {if (!nextExports) return;const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate("${id}", currentExports, nextExports);if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);});
});
`;return { code: result.code, map: sourceMap };},},options.plugins? {name: "vite:react-swc",apply: "build",enforce: "pre", // Run before esbuildconfig: (userConfig) => ({build: silenceUseClientWarning(userConfig),}),transform: (code, _id) =>transformWithOptions(_id.split("?")[0], code, "esnext", options, {runtime: "automatic",importSource: options.jsxImportSource,}),}: {name: "vite:react-swc",apply: "build",config: (userConfig) => ({build: silenceUseClientWarning(userConfig),esbuild: {jsx: "automatic",jsxImportSource: options.jsxImportSource,tsconfigRaw: {compilerOptions: { useDefineForClassFields: true },},},}),},];
};const transformWithOptions = async (id: string,code: string,target: JscTarget,options: Options,reactConfig: ReactConfig,
) => {const decorators = options?.tsDecorators ?? false;const parser: ParserConfig | undefined = options.parserConfig? options.parserConfig(id): id.endsWith(".tsx")? { syntax: "typescript", tsx: true, decorators }: id.endsWith(".ts") || id.endsWith(".mts")? { syntax: "typescript", tsx: false, decorators }: id.endsWith(".jsx")? { syntax: "ecmascript", jsx: true }: id.endsWith(".mdx")? // JSX is required to trigger fast refresh transformations, even if MDX already transforms it{ syntax: "ecmascript", jsx: true }: undefined;if (!parser) return;let result: Output;try {result = await transform(code, {filename: id,swcrc: false,configFile: false,sourceMaps: true,jsc: {target,parser,experimental: { plugins: options.plugins },transform: {useDefineForClassFields: true,react: reactConfig,},},});} catch (e: any) {const message: string = e.message;const fileStartIndex = message.indexOf("╭─[");if (fileStartIndex !== -1) {const match = message.slice(fileStartIndex).match(/:(\d+):(\d+)]/);if (match) {e.line = match[1];e.column = match[2];}}throw e;}return result;
};const silenceUseClientWarning = (userConfig: UserConfig): BuildOptions => ({rollupOptions: {onwarn(warning, defaultHandler) {if (warning.code === "MODULE_LEVEL_DIRECTIVE" &&warning.message.includes("use client")) {return;}if (userConfig.build?.rollupOptions?.onwarn) {userConfig.build.rollupOptions.onwarn(warning, defaultHandler);} else {defaultHandler(warning);}},},
});export default react;

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

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

相关文章

「深度解析」ChatGPT2:无监督多任务学习的语言模型(2019)

论文总结 以下是我阅读完整篇论文做的个人总结&#xff0c;包含了ChatGPT-2文章的主要内容&#xff0c;可以仅看【论文总结】章节。 数据集 自制了一个网页爬虫&#xff0c;被抓取的网页部分来自于社交平台&#xff0c;这些网页由人工进行过滤。最终生成 WebText数据集 &…

Django开发实战(1)- 认识django

1.django 使用MTV模式&#xff0c;其实与MVC本质一样&#xff1a; model&#xff1a;业务对象和关系映射&#xff08;ORM&#xff09; template&#xff1a;客户端页面展示 view&#xff1a;业务逻辑&#xff0c;根据需求调用 2.开发相关 √ python √ html&…

简单的手动实现spring中的自动装配案例

简简单单的实现一个spring中的自动装配和容器管理的小骚操作。 1&#xff0c;创建AutoSetBean.java 使用injectBeans静态方法&#xff0c;可以扫描指定包下的所有带MyInject注解的字段&#xff0c;如果在beans的Map中存在这个字段的实例化类&#xff0c;则执行装配。 import…

无人机企业需要什么资质?

无人机企业所需的资质主要可以分为几大类&#xff0c;以确保其合法、安全、高效地进行相关业务活动。以下是对这些资质的详细解释和归纳&#xff1a; 1. 基础企业资质&#xff1a; - 工商营业执照&#xff1a;这是企业合法经营的基本证书&#xff0c;所有企业都需要取得。无人…

软连接迁移 Docker 的默认安装(存储)目录

前言 经常我们会拿到一些别人装好的服务器&#xff0c;需要在这些系统上启动我们的docker服务。 但是这些“专业人员”呢&#xff0c;有时候就会有非常不专业的操作&#xff0c;比如他把根目录/只划分50GB&#xff0c;/home却有51TB。这个时候就会导致我们的服务器还有很多空间…

9 redis,memcached,nginx网络组件

课程目标: 1.网络模块要处理哪些事情 2.reactor是怎么处理这些事情的 3.reactor怎么封装 4.网络模块与业务逻辑的关系 5.怎么优化reactor? io函数 函数调用 都有两个作用:io检测 是否就绪 io操作 1. int clientfd = accept(listenfd, &addr, &len); 检测 全连接队列…

基于工业互联网的智慧矿山解决方案PPT(38页)

文章摘要 工业互联网与智慧矿山 基于工业互联网的新一代智慧矿山解决方案&#xff0c;将互联网和新一代IT技术与工业系统深度融合&#xff0c;形成关键的产业和应用生态&#xff0c;推动工业智能化发展。该方案以“四级、三层、两网、一平台”为总体框架&#xff0c;强调应用目…

刷代码随想录有感(127):动态规划——判断是否为子序列

题干&#xff1a; 代码&#xff1a; class Solution { public:bool isSubsequence(string s, string t) {vector<vector<int>>dp(s.size() 1, vector<int>(t.size() 1, 0));for(int i 1; i < s.size(); i){for(int j 1; j < t.size(); j){if(s[i …

Perl 语言开发(六):深入探索 Perl 中的数组与列表操作

目录 1. 数组和列表的基本概念 1.1 数组的定义与特点 1.2 列表的定义与特点 2. 数组的基本操作 2.1 访问数组元素 2.2 数组的长度 2.3 添加和删除元素 2.4 切片操作 2.5 迭代数组 3. 列表的常见操作 3.1 创建和使用列表 3.2 列表的上下文 3.3 列表和数组的转换 3…

【人工智能】-- 智能机器人

个人主页&#xff1a;欢迎来到 Papicatch的博客 课设专栏 &#xff1a;学生成绩管理系统 专业知识专栏&#xff1a; 专业知识 文章目录 &#x1f349;引言 &#x1f349;机器人介绍 &#x1f348;机器人硬件 &#x1f34d;机械结构 &#x1f34d;传感器 &#x1f34d;控…

【MySQL】简单的CURD操作

【MySQL】简单的CURD操作 前言 ​ 今天我们要一起学习的是MySQL中简单的CURD操作&#xff0c;Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09;。 正文 Create创建 创建数据的基本方式insert语法&#xff1a; INSER…

Linux查看文件的行数,字数,字节数

介绍 在Linux系统中这统计非常方便&#xff0c;只需要简单的几个命令就可以搞定&#xff0c;这个命令就是 wc。 wc --help 用法&#xff1a;wc [选项]... [文件]...或&#xff1a;wc [选项]... --files0-fromF 输出每个指定文件的行数、单词计数和字节数&#xff0c;如果指定…

One day for Chinese families

周围生活中的普通家庭的一天流程&#xff1a; 【上班的一天】 【放假的一天】 有家庭的人&#xff0c;上班流程&#xff1a; 01&#xff09;准备早餐&#xff0c;牛奶&#xff0c;面包 02&#xff09;叫娃娃起床&#xff0c;一般要蛮久的&#xff1b;沟通交流 -- 哄娃娃 -- 生气…

【TB作品】基于ATmega48的开机登录程序设计

使用Proteus仿真软件设计一个开机登录程序,单片机选用ATmegga48. 基础要求: 1.程序启动后在LCD1602液晶屏上提示用户通过独立按键输入密码(6位)。 2.密码输入错误则在屏幕上提示密码错误,密码输入正确则在屏幕上提示密 码正确后等待约3秒后进入主界面,在屏幕中央显示HelloWorld…

windows下编译ffmpeg 最详细教程

1 Ffmpeg下载地址&#xff1a;FFmpeg 使用命令下载 git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg 下载完成后会发现如下目录&#xff1a; 2 msys2下载地址&#xff1a;MSYS2 解压好后&#xff0c;选择一个非空路径安装&#xff0c;安装好后路径如下&#xff1a; 为…

自己动手实现语音识别

声音的本质是震动,震动的本质是位移关于时间的函数,波形文件(.wav)中记录了不同采样时刻的位移。 通过傅里叶变换,可以将时间域的声音函数分解为一系列不同频率的正弦函数的叠加,通过频率谱线的特殊分布,建立音频内容和文本的对应关系,以此作为模型训练的基础。 语音mfc…

ROS——坐标系管理、监听与广播、常用可视化工具

坐标系管理 TF功能包 小海龟追踪实验 ros版本(20.04)的tf安装命令: sudo apt-get install ros-noetic-turtle-tf 解决因python版本出现的无法生成跟随海龟&#xff1a; sudo ln -s /usr/bin/python3 /usr/bin/python ( -s 软链接,符号链接) ln命令&#xff08;英文全拼&#…

ForkJoinPool 简介

引言 在现代并行编程中&#xff0c;处理大规模任务时将任务分割成更小的子任务并行执行是一种常见的策略。Java 提供了 Fork/Join 框架来支持这一模式&#xff0c;其中 ForkJoinPool 是其核心组件。本文将详细介绍 ForkJoinPool 的概念、使用方法和实际应用。 1. ForkJoinPoo…

grpc-go服务端接口添加

【1】新建一个目录whgserviceproto&#xff0c;目录下新建一个proto包&#xff1a;whgserviceproto.proto &#xff08;注意目录和包名称保持一致&#xff09; //协议为proto3 syntax "proto3"; // 指定生成的Go代码在你项目中的导入路径 option go_package"…

代理模式详解、RESTFul风格、Spring IOC

Day49 代理模式proxy 概念&#xff1a; 代理(Proxy)是一种设计模式&#xff0c;提供了对目标对象另外的访问方式&#xff0c;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 代理模式分为静态代理和动态代理…