前端UI组件库的打包与发布

news/2025/1/30 20:17:40/

UI组件库的打包是指“将开发完成的业务代码处理成可在生产环境中运行,并供用户在浏览器上使用”的过程。浏览器可以视为用户使用的生产环境,除浏览器外,常见的生产环境还有Node.js。Node.js通常是现代前端开发过程所运行的环境,例如我们常在Node.js环境下使用Vue和React,相当于Node.js是它们的生产环境。Node.js在13.2.0版本之前仅支持CommonJS模块,在13.2.0版本之后才开始支持ESM模块。为了让开发人员在不同版本的Node.js环境下运行UI组件库,需要提供CommonJS和ESM两种模式来打包UI组件库。
除上述环境外,打包UI组件库后的代码会进行压缩处理,需要通过source map文件映射回未压缩的代码,方便开发人员调试以及定位代码的出错位置,最后还要将scss文件打包成传统的css文件,用于提供全量UI组件库的css样式。在UI组件库的打包过程中,需要完成的工作如下:

  1. 提供浏览器端的代码包,可以是UMD或IIFE。
  2. 提供Node.js环境的CommonJS模块和ESM模块代码包。
  3. 提供全局引入的css样式,并按需加载css样式。
  4. 提供source map文件。
  5. 对UI组件库打包的代码进行压缩。

了解Rollup

Rollup是一个用于js模块的打包工具,它将小的代码片段编译成更大,更复杂的代码,例如库或应用程序。 它使用ES6版本的js中包含的新标准化代码模块格式,而不是以往的CommonJS和AMD等特殊解决方案。
Rollup的配置简单直观,能够生成轻量、高效的构建文件,尤其适用于构建JS库或框架。它还支持代码拆分、按需加载等功能,有助于优化和提升前端应用的性能。

Rollup具有以下特点。

  • 高效:Rollup通过静态分析的方式,只打包必要的代码和依赖,打包过程更高效,打包后的产物也更小。
  • 可扩展性强:Rollup支持各种插件和加载器扩展其功能,可以轻松地与Babel、ts、eslint等工具集成。
  • 模块化:Rollup基于ES6模块,支持使用ES6模块化地语法和特性,例如import和export。
  • 代码分割:Rollup支持将代码分割成多个小块,并支持按需加载或并行加载,以优化性能。
  • Tree Shaking:Rollup可以消除不必要地代码和依赖,以减少最终地产物大小。
  • 多格式输出:AMD、CommonJS、ES6 modules、UMD、IIFE、等。

使用Rollup打包UI组件库只需进行全局安装,在终端执行指令npm install --global rollup。

接下来的UI组件库打包过程将围绕Rollup的JS API特性展开,实现UMD、ES以及CJS这3种模块的打包。

初始化Build打包目录

Rollup有以下两种配置方式。

  • 配置文件+命令行:可以提供一个可选的Rollup配置文件,以简化命令行的使用,并启用高级Rollup功能。
  • JS API:一个可以在Nodejs中使用的JS API。这种方式相比起第一种方式会更加灵活。

新建build目录,并在build目录下执行npm init -y,为build生成package.json文件作为一个打包工具包。

Rollup的基础配置

如果你的ui组件库是使用Vue开发的,打包UI组件库就是将Vue文件编译成JS文件的过程,如果使用了ts,同样需要将以.ts为后缀的文件编译成js文件。在rollup中,推荐使用@vitejs/plugin-vue插件识别vue文件,使用@rollup/plugin-node-resolve插件解析npm包。对于ts,则可以使用rollup-plugin-esbuild插件进行编译。

根据上述说明,首先在build目录下安装上述3个插件。

{"name": "build","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC","devDependencies": {"@rollup/plugin-node-resolve": "^16.0.0","@vitejs/plugin-vue": "^5.2.1","rollup": "^4.30.1","rollup-plugin-esbuild": "^6.1.1"}
}

Rollup打包主要有4个步骤:

  1. 配置打包入口文件。
  2. 配置所需插件。
  3. 配置输出文件格式。
  4. 打包输出目录。

在build目录下新建src目录以及umdBuild.js文件,用于实现umd格式的打包,代码如下:

import { rollup } from "rollup";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import vue from "@vitejs/plugin-vue";
import esbuild from "rollup-plugin-esbuild";
/*** node.js 核心方法 url、path*/
import { resolve } from "path";
import { pkgRoot, outputUmd } from "./common.js"
// umd打包
export const umdBuildEntry = async () => {const writeBundles = await rollup({input: resolve(pkgRoot, "index.js"),   // 配置打包入口文件plugins: [   // 配置插件vue(),nodeResolve({ extensions: ['.ts'] }),esbuild(),],external: ["vue"],  // 排除不进行打包的npm包});writeBundles.write({})
};
umdBuildEntry()

配置打包路径

在打包UI组件库时需要配置打包文件的入口、插件、格式和输出目录。

/*** node.js 核心方法 url、path*/
//common.js
import { fileURLToPath } from "url";
import { resolve, dirname } from "path";
export const outputPkgDir = 'hzu'//输出目录
export const filePath = fileURLToPath(import.meta.url);
export const dirName = dirname(filePath);
export const rootDir = resolve(dirName, "..", ".."); // 获取UI组件库 “根目录”
export const pkgRoot = resolve(rootDir, "packages"); // 获取UI组件包的目录,入口
console.log('filePath', filePath)
console.log('dirName', dirName)
console.log('rootDir', rootDir)
console.log('pkgRoot', pkgRoot)export const outputDir = resolve(rootDir, outputPkgDir)
// es
export const outputEsm = resolve(rootDir, outputPkgDir, "es")
// lib
export const outputCjs = resolve(rootDir, outputPkgDir, "lib")
// dist
export const outputUmd = resolve(rootDir, outputPkgDir, "dist")

UMD打包

UMD打包是一种将js库或模块打包成可以在不同环境中使用的通用格式的方法。UMD打包同时兼容CommonJS、AMD和全局变量的使用方式,因此可以在项目的<script>中引入通过UMD打包后的产物,直接在浏览器中以访问全局变量的方式使用。

输出UMD组件包

完成了UI组件库打包文件入口的路径后,在打包时,只需要配置打包文件格式的模式以及打包后产物出书的目录即可。

import { rollup } from "rollup";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import vue from "@vitejs/plugin-vue";
import esbuild from "rollup-plugin-esbuild";
/*** node.js 核心方法 url、path*/
import { resolve } from "path";
import { pkgRoot, outputUmd } from "./common.js"
// umd打包
export const umdBuildEntry = async () => {const writeBundles = await rollup({input: resolve(pkgRoot, "index.js"),   // 配置打包入口文件plugins: [   // 配置插件vue(),nodeResolve({ extensions: ['.ts'] }),esbuild(),],external: ["vue"],  // 排除不进行打包的npm包});writeBundles.write({format: "umd",//指定生成的包的格式。这里是“全量打包”,也就是通用模块,定义格式为“umd”file: resolve(outputUmd, "index.full.js"),//生成指定的文件。name: "HzuUI",//自定义包的全局变量名称,也是打包后的产物可以访问的变量名称。将属性format指定为iife或umd打包格式,属性name是必选的globals: {//定义UI组件库打包后所需要依赖的变量。目前,我们开发的UI组件库使用的是Vue.js 3,因此需要告诉Rollup,Vue是外部依赖的,vue模块的全局变量是“Vue”vue: "Vue",},})
};
umdBuildEntry()

然后进入build/src目录,并在终端执行命令行node ./umdBuild.js,打包生成UMD格式的组件包。

ESM、CJS模块化打包

ESM和CJS是js中使用的不同模块。ESM是现代浏览器和Node.js支持的标准模块,CJS是传统意义上在Node.js中使用的模块系统。
ESM是ECMAScript标准中定义的模块化规范,它是现代js开发中推荐的模块化方案。ESM分别使用import和export关键字来导入和导出模块。
CommonJS是Node.js中使用的模块化规范,也可以在其他环境中使用,如使用Rollup、Browserify、Webpack等工具进行打包。CommonJS分别使用require和module.exports来导入和导出模块。

ESM、CJS打包输出

UMD包属于全量模式打包,也就是将所有的组件打包为一份js文件,通过在浏览器中使用<script>标签引入组件。经过UMD打包的文件大,并且无法支持按需加载。为了使打包的组件库支持按需加载模式,需要使用ESM和CJS打包模式实现按需加载,也可以在打包过程中实现Tree shaking(去除js中无用的代码)优化。

import glob from "fast-glob";
import { rollup } from "rollup";
import path from 'path'
import { nodeResolve } from "@rollup/plugin-node-resolve";
import postcss from "rollup-plugin-postcss"
import vue from "@vitejs/plugin-vue";
import esbuild from "rollup-plugin-esbuild";
/*** node.js 核心方法 url、path*/import { pkgRoot, outputEsm, outputCjs, outputPkgDir } from "./common.js"//打包入口文件
export const moduleBuildEntry = async () => {const input = await glob("**/*.{js,ts,vue}", {cwd: pkgRoot,absolute: true,  // 绝对路径onlyFiles: true, // 文件的路径,不需要目录})//获取的文件使array数据的集合const writeBundles = await rollup({input,   // 配置打包入口文件plugins: [   // 配置插件compileStyleEntry(),vue(),nodeResolve({ extensions: ['.ts'] }),esbuild(),postcss({pextract: true,  // css通过链接引入}),],external: [ // 排除不进行打包的npm包'vue','@vueuse/core','async-validator',],  });writeBundles.write({format: "esm",//打包格式dir: outputEsm,//打包后组件输出的目录preserveModules: true,//使打包后的组件库模块结构和源码的模块结构保持一致,需要设置为trueentryFileNames: `[name].mjs`,//入口文件名称。sourcemap: true,})writeBundles.write({format: "cjs",dir: outputCjs,preserveModules: true,entryFileNames: `[name].cjs`,sourcemap: true,});
};// 重写@import路径,重写每个组件style/index.js引用样式的路径
const compileStyleEntry = () => {const themeEntryPrefix = `@ui-library/theme/src/`return {name: 'compile-style-entry',resolveId (id) {if (!id.startsWith(themeEntryPrefix)) return return {id: id.replaceAll(themeEntryPrefix, `${outputPkgDir}/theme/src/`),external: 'absolute',}}}
}moduleBuildEntry()

测试模块化组件包

完成组件库打包后,可以在本地模拟npm包测试,无须发布至npm官网。在本地模拟npm包中,通过npm link命令与全局node_modules包建立全局链接。

{"name": "hzu","version": "1.0.0","description": "自定义组件包","main": "./lib/index.cjs","module": "./es/index.mjs","directories": {"lib": "lib"},"scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC"
}
  1. 建立全局链接
    每个npm包中都有一个package.json文件,本地模拟npm包也不例外。进入hzu目录,执行npm init -y命令,自动生成package.json文件。在package.json文件中定义main和module两个关键字,分别指向打包后的lib/index.cjs和es/index.mjs,然后执行命令npm link。npm link命令可以为一个任意位置的npm包与全局的node_module建立链接,在系统中做快捷映射,建立链接之后即可在本地进行模拟测试。

  2. 本地测试
    安装打包后的组件包,进行目标目录(一般是前端工程)执行命令npm link hzu。hzu是package.json文件属性name的值,也就是包的名称。

3.全局引入

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import UILibrary from 'hzu'//引入examples目录node_modules目录中的hzu依赖,而不是之前工程中的packages开发包
//import UILibrary from "../../packages" 
import '@ui-library/theme/src/index.scss' //全量引入组件样式const app = createApp(App)
app.use(UILibrary) //全局注册组件,如果按需加载可以屏蔽该行代码
app.mount('#app')

4.按需引入

<script setup>
//import { HzuMessage, HzuMessageBox} from '@ui-library/components';
//import { Close, Eye,Show,Hide  } from '@ui-library/icons';
//import { HzuButton } from '@ui-library/components';import { HzuMessage, HzuMessageBox} from 'hzu';
import { Close, Eye,Show,Hide  } from 'hzu';
import { ref, h } from 'vue';import { HzuButton } from 'hzu'; //如果使用全局注册组件,那么只需要在main.js引入即可,如果是按需加载组件,那么就需要在用到的地方import
</script>

Gulp打包scss文件

scss文件基本上是现代前端开发的标配,但是浏览器并不支持scss文件,因此需要将scss文件编译为css文件。

gulp-sass是一个Gulp插件,用于将scss文件编译成css文件。
gulp-sass的优势如下:

  • 高效性:gulp-sass可以快速将scss文件编译成css文件,提高开发效率。
  • 实时预览:结合浏览器自动刷新等工具,实时预览更改后的样式。
  • 易于配置:灵活的选项和参数允许开发人员根据需求定制编译过程。

使用gulp-sass需要先安装gulp和gulp-sass依赖包,执行以下命令:

  • npm install gulp
  • npm install gulp-sass //高于4版本的是不自带sass编译器的,因此还需要安装sass编译器的包
  • npm install sass

全量打包css和按需加载打包css

全量打包css是指将所有组件的css文件合并为一个单独的文件。全量打包的优势在于减少http请求次数,提高页面加载速度,并简化管理和部署过程。然而,需要注意的是,全量打包css可能导致文件体积过大,反而影响网页性能。因此,在全量打包css时,需要考虑对css文件进行压缩和优化,以确保在减少请求次数的同时,保持较小的文件大小和高效的加载速度。

按需加载打包css的方式和全量打包css类似,只是指定的入口和输出的目录不同。

在build目录下新建styleBuild.js文件,用于打包css样式,并引入gulp和gulp-sass,代码如下:

import gulp from "gulp";
import dartSass from "sass";
import gulpSass from "gulp-sass";
import autoprefixer from "gulp-autoprefixer";
import cleanCSS from "gulp-clean-css";
import gulpConcat from "gulp-concat";
//删除文件或者文件夹
import { deleteAsync } from "del"
import { rootDir, pkgRoot, outputDir, outputUmd } from "./common.js";
/*** 按需加载打包CSS*/
const buildScssModules = async () => {const sass = gulpSass(dartSass);await new Promise((resolve) => {gulp.src(`${rootDir}/packages/theme/src/**/*.scss`).pipe(sass.sync()) // 编译.pipe(autoprefixer({ cascade: false })) // 兼容.pipe(cleanCSS()) // 压缩.pipe(gulp.dest(`${outputDir}/theme`)).on("end", resolve); // 监听流完成});deleteFiles()
};/*** 全量打包CSS*/
const buildScssFull = async () => {const sass = gulpSass(dartSass);await new Promise((resolve) => {gulp.src(`${pkgRoot}/theme/src/index.scss`)//指定打包入口.pipe(sass.sync()) // 编译.pipe(autoprefixer({ cascade: false })) // 兼容浏览器,自动根据所使用的css属性添加浏览器前缀,如-webkit-、-ms-等.pipe(cleanCSS()) // 压缩css.pipe(gulpConcat('index.min.css'))//合并到指定文件.pipe(gulp.dest(outputUmd)) // dist.on("end", resolve); // 监听流完成});
};/*** 拷贝scss*/
const cloneScss = async () => {await new Promise((resolve) => {gulp.src(`${pkgRoot}/theme/src/**/*`).pipe(gulp.dest(`${outputDir}/theme/src`)).on("end", resolve); // 监听流完成});
}/*** 删除指定文件或文件夹*/
const deleteFiles = async () => {await deleteAsync([`${outputDir}/theme/index.css`, `${outputDir}/theme/common`], //index.css是全量打包css,common目录是在开发ui组件库时定义的scss变量和混合指令,都可以删除{ force: true }//设置为true,表示可以跨当前目录删除文件)
}export const buildStyle = async () => {await Promise.all([cloneScss(), buildScssFull(), buildScssModules()]);
};
buildStyle()

Gulp多任务

Gulp多任务是指一种功能强大的机制,允许用户定义一组相关的任务进行批量处理,无须单独定义和调用每个任务。这种机制允许用户以模块化的方式住址构建过程,并避免编写重复的代码。

series()和parallerl()

Gulp执行多任务的常用方式分为串行和并行,分别对应series()和parallerl()。可以简单理解为:串行时一个一个任务执行,只有上一个任务执行完成,才会进入下一个任务,并行是可以同时执行多个任务。

在打包UI组件库时,包含UMD、ESM和CJS和CSS样式以及删除等动作,属于多任务,由于打包时执行的任务并不多,并且各个函数之间不存在相互依赖关系,因此可以使用串行或并行方式。

//index.js
export * from "./files.js"
export * from "./umdBuild.js"
export * from "./moduleBuild.js"
export * from "./styleBuild.js"//gulpgile.js
import gulp from "gulp";
import { deletePkg, umdBuildEntry, moduleBuildEntry, buildStyle, copyPackage  } from "./src/index.js"export default gulp.series(gulp.series(deletePkg, umdBuildEntry, moduleBuildEntry, buildStyle, copyPackage )
)//files.jsimport gulp from "gulp";
//删除文件或者文件夹
import { deleteAsync } from "del"
import { outputDir, pkgRoot } from "./common.js"/*** 存在包,则先删除,确保ui组件库是最新的的文件,如果没有不删除组件包,那么会遗留历史文件*/
export const deletePkg = async () => {await deleteAsync([outputDir], { force: true })
}//npm包和package.json文件之间有着密切的关系,package.json文件是npm包的清单和配置文件,它给出了一个node项目的基本信息、依赖项和允许脚本,并标识了项目的名称和版本号。npm包的发布需要package.json文件存在,并且必须有package.json文件的属性name和version,如果没有,则无法正常执行npm install命令。
//在package目录下新建package.json文件,复制该文件
// 复制package.json
export const copyPackage = async () => {await new Promise((resolve) => {gulp.src(`${pkgRoot}/package.json`).pipe(gulp.dest(`${outputDir}`)).on("end", resolve); // 监听流完成});
}//buid/package.json
"scripts": {"start": "gulp --require @esbuild-kit/cjs-loader -f gulpfile.js","test": "echo \"Error: no test specified\" && exit 1"},

整个工程目录如下所示:
在这里插入图片描述

npm发布

npm是node.js的一个包管理器和分发工具。npm是node.js平台默认的包管理工具,也是世界上最大的软件注册表,包含超过60万个包的结构,可以使用户轻松跟踪依赖项和版本。npm是一个开放源代码的命令行工具,用于安装,更新和管理node模块。它允许用户从一个集中的仓库中下载和安装公共的node模块。npm随着node一起安装,解决了node代码部署中的许多问题,如包的管理(包括安装、卸载、更新、查看、搜索、发布等),并详细记录了每个包的信息(包括作者、版本、依赖、授权信息等),从而将开发人员从繁琐的包管理工作中解放出来,专注于功能的开发。

package.json文件

package.json是一个基于json格式的文件,它在node.js、前端项目、包管理器等项目中扮演这非常重要的角色。package.json出出现在node.js应用程序或者模块的根目录中,充当项目的清单文件。package.json文件中包含项目的各种必要信息,包括但不限于项目名称、版本、描述、作者、许可证信息,以及更重要的依赖关系管理和脚本定义。

package.json包含的字段如下:

  • name:包的名称,显示在npm平台中的名称,用户使用安装、引用包的名称。
  • version:包版本号。格式为“主版本号.次版本号.修订号-先行版(alpha/beta).公测修正版”,如1.0.0-alpha、1.0.0-rc.1。如果存在相同的版本号,则无法发布至npm平台。
  • private:是否私有。发布至npm时将其设置为false。
  • author:项目的作者信息。
  • contributors:项目贡献者,由多个人组成,如[{name:“xxxx”,emial:“”}]。
  • keywords:包的关键词。字符串数组,用于增加包的曝光量。在npm平台中搜索,在结果列表中可以看到搜索的包和对应的描述。
  • description:项目的简要描述,用于增加包的曝光率。作用与keywords类似。
  • main:指定commonjs或es模块的入口文件。
  • module:指定es模块入口文件。
  • scripts:用于定义运行命令的脚本。
  • dependencies:项目依赖的生产环境包。
  • devDependencies:项目依赖的开发环境包。
  • peerDependencies:对等依赖包。提示用户需要安装peerDependencies所指定依赖的包。可以简单理解为:对于我们开发的库、插件等,需要指定某个范围版本的依赖包才能正常运行,如果它们不是在指定范围内的版本,则会报错或发出警告。
  • sideEffects:用于标识某些模块时无副作用的,不应该被Tree-shaking移除。
  • license:项目的许可证信息。开源许可证是一种法律协议,用于明确开源软件的使用规则,可以选择ISC、MIT。
  • homepage:主页信息,项目首页的url地址。
  • bugs:问题反馈的url地址,可以是email地址。如bugs:{url:‘xxxx’,email:“xxxx”}。
  • responsity:项目源代码仓库所在位置,如responsity:{type:“git”,url:“git+https://github.com/xxxx.git”}。
版本号范围
^1.2.3>=1.2.3 ~ <2.0.0-0
^0.2.3>=0.2.3 ~ <0.3.0-0
^0.0.3>=0.0.3 ~ <0.0.4-0
^1>=1.0.0 ~ <2.0.0-0
~1.2.3>=1.2.3 ~ <1.3.0
~1.2>=1.2.0 ~ <1.3.0
~1>=1.0.0 ~ <2.0.0
  • npm1、npm2版本
    如果出现主项目和工具包共同所需的依赖包版本不兼容的情况,那么会使主项目依赖一个包,工具包依赖一个包。
  • npm3~npm6版本
    如果出现主项目和工具包共同所需要的依赖包版本不兼容的情况,会出现提示警告,并需要自己手动安装依赖。
  • npm7以及以上版本
    如果出现主项目和工具包共同所需的依赖包版本不兼容的情况,会提示错误信息,无法完成对包的依赖。

发布组件库

在npm官方网站中注册自己的账号,并在npm平台中确认是否存在和package.json文件的name属性相同名称的组件包,如果存在,则需要修改name的值,确保其是唯一的。

  1. 命令行登录
    在根目录终端中执行pnpm run build命令打包成功后,会自动生成hzu组件包,然后进入hzu目录,在终端中执行命令npm login,登录npm平台,在登录过程中需要输入账号、密码、邮箱、验证码等。
  2. 浏览器登录
    如果你安装的是9版本以上的npm,那么在终端执行npm login命令时,会提示你按下“ENTER”键。
  3. 发布确定镜像源
    发布确定镜像源是为了确定发布的平台,由于在开发项目过程中可能使用了非npm官方的镜像源,如cnpm镜像等。因此,为了将项目顺利发布至npm官方平台,可以先执行命令行npm config set registry=https://registry.npmjs.org,将镜像源改到npm官方平台。然后执行npm login,登录成功后,在执行npm publish。

http://www.ppmy.cn/news/1567968.html

相关文章

2024 CVPR Highlight Learning-Feedback

图像增强 Towards Robust Event-guided Low-Light Image Enhancement: A Large-Scale Real-World Event-Image Dataset and Novel Approach 解决的主要问题是低光照条件下的图像增强 通过多尺度整体融合分支提取事件和图像的结构和纹理信息&#xff0c;并引入信噪比&#xff0…

Ansible介绍与入门学习

一、Ansible的介绍&#xff08;Ansible is a radically simple IT automation engine 极简的IT自动化工具&#xff09; 1.Ansible是一款 运维的自动化工具&#xff0c;常用于软件部署自动化、配置自动化、管理自动化等&#xff0c;其内置大量的功能模块来满足日常的工作需要…

深入学习华为IPD流程之华为-PDT经理角色认知培训教材

本文介绍了PDT经理的角色认知,包括其在IPD体系中的位置、基本角色定位、关键管理活动、能力模型和评估方法以及培养路径。文章指出PDT经理是重量级产品开发团队的管理者,负责产品的商业成功和跨功能部门合作,通过绩效管理加强团队凝聚力,对商业结果负责。 重点内容: 1. …

OSPF邻接关系无法建立之MTU问题

OSPF中路由器间从邻居到建立完全邻接需满足以下条件: 1、邻居之间网络通 2、建立邻接的接口不能为OSPF被动接口 3、两台路由器的HELLO时间间隔和DEAD时间间隔必须一致 4、两台路由器的router-id 必须不同 5、如果开了OSPF认证,认证方式和KEY必须一致 6、两台路由器建立…

Vue.js 传递路由参数和查询参数

Vue.js 传递路由参数和查询参数 在 Vue.js 开发中&#xff0c;Vue Router 提供了灵活的方式来处理路由参数和查询参数&#xff0c;使得组件能够根据不同的路径或查询条件渲染相应的内容。 路由参数 路由参数&#xff08;也称为路径参数&#xff09;是 URL 路径的一部分&…

【Unity】 HTFramework框架(五十九)快速开发编辑器工具(Assembly Viewer + ILSpy)

更新日期&#xff1a;2025年1月23日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 开发编辑器工具MouseRayTarget焦点视角Collider线框Assembly Viewer搜索程序集ILSpy反编译程序集搜索GizmosElement类找到Gizmos菜单找到Gizmos窗口分析A…

react native在windows环境搭建并使用脚手架新建工程

截止到2024-1-11&#xff0c;使用的主要软件的版本如下&#xff1a; 软件实体版本react-native0.77.0react18.3.1react-native-community/cli15.0.1Android Studio2022.3.1 Patch3Android SDKAndroid SDK Platform 34 35Android SDKAndroid SDK Tools 34 35Android SDKIntel x…

自定义数据集,使用 PyTorch 框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测

在本文中&#xff0c;我们将展示如何使用 NumPy 创建自定义数据集&#xff0c;利用 PyTorch 实现一个简单的逻辑回归模型&#xff0c;并在训练完成后保存该模型&#xff0c;最后加载模型并用它进行预测。 1. 创建自定义数据集 首先&#xff0c;我们使用 NumPy 创建一个简单的…