当前位置: 首页 > news >正文

微信小程序npm扩展能力探究

文章目录

  • 创建 package.json
  • 使用 npm 包
    • 使用构建后的包自定义组件
    • 小程序 js 中引入构建后的包
  • npm 构建方式
    • 默认方式
      • 构建前
      • 构建后
    • 自定义 node_modules 和 miniprogram_npm 位置的构建方式
      • 用法
      • 构建前
      • 构建后
  • 发布小程序 npm 包
    • 发布新包的约束
    • 改造已有包的约束
    • 进行发布
  • 原理介绍
  • 开发第三方自定义组件
  • miniprogram_npm 组件寻址顺序

小程序支持使用 npm 安装第三方包。

创建 package.json

可以在小程序终端执行 npm init,逐个输入项目信息,或执行快捷命令 npm init -y,自动填充信息,两种方式最终都会生成 package.json 文件。

使用 npm 包

  1. package.json 所在的目录执行命令安装 npm 包:npm i,在同级形成 node_modules 目录。
  2. 点击开发者工具中的菜单栏:工具 --> 构建 npm
  3. 构建完成后会在同级创建 miniprogram_npm 目录,构建后的包均在该目录下。

看到这里你大概知道了,小程序中不会直接引用 node_modules 中的包,而是需要进行构建,构建后的包才是小程序可用的包。

一般情况下,package.json 放在项目根目录中,因此原始 node_modules 目录与构建后的 miniprogram_npm 目录都会在根目录中。

使用构建后的包自定义组件

{"usingComponents": {"myPackage": "packageName","package-other": "packageName/other"}
}

这里我们以使用 vant(小程序版) 为例。首先进行下载:

# 通过 npm 安装
npm i @vant/weapp -S --production# 通过 yarn 安装
yarn add @vant/weapp --production

执行构建,出现 miniprogram_npm 目录,那我们开始引入 Button 按钮组件,在全局文件 app.json 或 页面 page.json 中引入组件。

"usingComponents": {"van-button": "@vant/weapp/button/index"
}

在页面 wxml 文件中进行使用:

<van-button type="default">默认按钮</van-button>
<van-button type="primary">主要按钮</van-button>
<van-button type="info">信息按钮</van-button>
<van-button type="warning">警告按钮</van-button>
<van-button type="danger">危险按钮</van-button>

接着看到模拟器显示了我们引入的按钮。好了,到这里是不是很兴奋,我们终于可以继续使用我们在其他端用的顺手的组件库了。

小程序 js 中引入构建后的包

const myPackage = require('packageName')
const packageOther = require('packageName/other')

以下为官方提供的 js 模块 sm-crypto为例,首先进行下载:

npm i -S miniprogram-sm-crypto

执行构建,然后在 js 文件中进行引入:

const sm2 = require('miniprogram-sm-crypto').sm2
console.log(sm2)

可在调试器 console 上看到打印的信息。到这我们可以使用 js 编写的函数库了。

npm 构建方式

接下来我们该了解下 node_modules 包构建后形成 miniprogram_npm 包的方式及过程。

构建是依据 package.json 的 dependencies 字段,所以声明在 devDependencies 里的包可以在开发过程中被安装使用而不会参与到构建中。如果是开发者工具 v1.02.1811150 之前的版本,则建议使用 --production 选项,可以减少一些业务无关的 npm 安装包,从而减少整个小程序包的大小。

目前提供了两种构建 npm 的方式。

默认方式

默认情况,项目根目录中 project.config.json 文件中字段 miniprogramRoot 指定小程序源码的目录(需为相对路径),当该字段不存在时,miniprogramRoot 就是 project.config.json 所在的目录。

在每个 package.json 执行 npm i 之后,其构建 npm 的结果是,为每一个 package.json 对应的 node_modules 构建一份 miniprogram_npm,并放置在同级目录中。

构建前

├── miniprogram
│   ├── app.js
│   ├── app.json
│   ├── app.wxss
│   ├── index
│   │   ├── 略
│   ├── node_modules // 可被默认方式构建 npm,因为它在 miniprogramRoot 内
│   ├── package.json
│   └── sub_package
│       ├── node_modules // 可被默认方式构建 npm,因为它在 miniprogramRoot 内
│       ├── package.json
│       └── sub_package_page
├── node_modules // 不被默认方式构建 npm,因为它不在 miniprogramRoot 指定的目录内
├── package.json
└── project.config.json // 其中存在配置 "miniprogramRoot": "./miniprogram"

构建后

├── miniprogram
│   ├── app.js
│   ├── app.json
│   ├── app.wxss
│   ├── index
│   │   ├── 略
│   ├── miniprogram_npm
│   ├── node_modules // 可被默认方式构建 npm,因为它在 miniprogramRoot 内 --> 同级的 miniprogram_npm 是这份 node_modules 的构建结果
│   ├── package.json
│   └── sub_package
│       ├── miniprogram_npm 
│       ├── node_modules // 可被默认方式构建 npm,因为它在 miniprogramRoot 内 --> 同级的 miniprogram_npm 是这份 node_modules 的构建结果
│       ├── package.json
│       └── sub_package_page
├── node_modules // 不被默认方式构建 npm,因为它不在 miniprogramRoot 指定的目录内 --> 它并没有对应的 miniprogram_npm 生成
├── package.json
└── project.config.json // 其中存在配置 "miniprogramRoot": "./miniprogram"

可以参考例子 demo,实际构建下,会让你理解的更为深刻。

自定义 node_modules 和 miniprogram_npm 位置的构建方式

此处要求参与构建 npm 的 package.json 文件需要在 project.config.json 定义的 miniprogramRoot 目录中。

与默认方式不一样,此种方式需要开发者在 project.config.json 中指定 node_modules 的位置和构建产物 miniprogram_npm 的位置。

用法

  • 配置 project.config.json 的 setting.packNpmManuallytrue,开启自定义 node_modulesminiprogram_npm 位置的构建方式
  • 配置 project.config.json 的 setting.packNpmRelationList 项,指定 packageJsonPathminiprogramNpmDistDir 的位置

其中 packNpmRelationList 用 TS 表示数据结构为:

packNpmRelationList: Array<{"packageJsonPath": string,"miniprogramNpmDistDir": string
}>
  • packageJsonPath 表示 node_modules 所对应的 package.json
  • miniprogramNpmDistDir 表示 node_modules 的构建结果 miniprogram_npm 位置

构建前

├── miniprogram
│   ├── app.js
│   ├── app.json
│   ├── app.wxss
│   ├── index
│   ├── sitemap.json
│   └── sub_package
│       └── sub_package_page
├── project.config.json
├── src_node_modules_1
│   ├── node_modules
│   └── package.json
└── src_node_modules_2├── node_modules└── package.json

其中 project.config.json 存在配置

"setting": {"packNpmManually": true,"packNpmRelationList": [{"packageJsonPath": "./src_node_modules_1/package.json","miniprogramNpmDistDir": "./miniprogram/"},{"packageJsonPath": "./src_node_modules_2/package.json","miniprogramNpmDistDir": "./miniprogram/sub_package"}]
}

构建后

├── miniprogram
│   ├── app.js
│   ├── app.json
│   ├── app.wxss
│   ├── index
│   ├── miniprogram_npm // 由 src_node_modules_1/node_modules 构建得到
│   ├── sitemap.json
│   └── sub_package
│       ├── miniprogram_npm // 由 src_node_modules_2/node_modules 构建得到
│       └── sub_package_page
├── project.config.json
├── src_node_modules_1
│   ├── node_modules
│   └── package.json
└── src_node_modules_2├── node_modules└── package.json

可以参考例子 demo,实际构建下,会让你理解的更为深刻。

发布小程序 npm 包

发布新包的约束

这里要发布的 npm 包是特指专为小程序定制的 npm 包(下称小程序 npm 包)。因为小程序自定义组件的特殊性,原有的 npm 包机制无法满足我们的需求,所以这里需要对小程序 npm 包做一些约束:

  1. 小程序 npm 包要求根目录下必须有构建文件生成目录(默认为 dist 目录),此目录可以通过在 package.json 文件中新增一个 miniprogram 字段来指定,比如:
{"name": "miniprogram-custom-component","version": "1.0.0","description": "","miniprogram": "dist","devDependencies": {},"dependencies": {}
}

该 miniprogram 字段在编辑器进行 构建 npm 时,将该字段值的目录文件复制到 miniprogram_npm 目录下的同名包中。

  1. 小程序 npm 包里只有构建文件生成目录会被算入小程序包的占用空间,上传小程序代码时也只会上传该目录的代码。如果小程序 npm 包有一些测试、构建相关的代码请放到构建文件生成目录外。另外也可以使用 .npmignore 文件来避免将一些非业务代码文件发布到 npm 中。

  2. 测试、构建相关的依赖请放入 devDependencies 字段中避免被一起打包到小程序包中。

改造已有包的约束

如果是已经发布过的一些 npm 包,因为一些原因无法改造成小程序 npm 包的结构的话,也可以通过微调后被使用,但是请确保遵循以下几点:

  1. 只支持纯 js 包,不支持自定义组件。
  2. 必须有入口文件,即需要保证 package.json 中的 main 字段是指向一个正确的入口,如果 package.json 中没有 main 字段,则以 npm 包根目录下的 index.js 作为入口文件。
  3. 测试、构建相关的依赖请放入 devDependencies 字段中避免被一起打包到小程序包中,这一点和小程序 npm 包的要求相同。
  4. 不支持依赖 c++ addon,不支持依赖 nodejs 的内置库:
const addon = require('./addon.node'); // 不支持!
const http = require('http'); // 不支持!
  1. 小程序环境比较特殊,一些全局变量(如 window 对象,document 对象)和构造器(如 Function 构造器)是无法使用的。
  2. 对于一些纯 js 实现的 nodejs 内置库(如 path 模块),可以通过额外安装其他开发者实现的 npm 包来支持。
  3. 此处使用 npm 包时如果只引入包名,则默认寻找包名下的 index.js 文件或者 index 组件。
  4. 使用 require 依赖的时候下列几种方式也是不允许的:
// 不允许将 require 赋值给其他变量后再使用,以下代码不会去解析出具体依赖
let r;
r = require;
r('testa');let r2 = require;
r2('testa');// 不允许 require 一个变量,以下代码依赖运行时,无法解析出具体依赖
let m = 'testa';
require(m);

进行发布

发布 npm 包流程可以参考这篇文章公共资源包发布流程详解

原理介绍

为了帮助大家更好的理解发布 npm 包中提到的各种要求,这里简单介绍一下原理:

  1. 首先 node_modules 目录中的代码不会参与小程序代码的编译、打包和上传,小程序仅能使用 npm 构建后形成的 miniprogram_npm 目录中的包。
  2. 构建打包分为两种:一种是:小程序 npm 包会直接拷贝构建后生成的目录文件(如在 package.json 文件中 miniprogram 指定为 dist)到 miniprogram_npm 中;另一种是:npm 包则会从入口 js 文件开始走一遍依赖分析和打包过程(类似 webpack)。
  3. 寻找小程序可用的 npm 包的过程和 常规 npm 的实现类似,从依赖 npm 包的文件所在目录开始逐层往外找,直到找到可用的 npm 包或是小程序根目录为止。

下面简单介绍下构建打包前后的目录情况。

构建之前的结构:

|--node_modules
|    |--testComp // 小程序 npm 包
|    |    |--package.json
|    |    |--src
|    |    |--miniprogram_dist
|    |         |-index.js
|    |         |-index.json
|    |         |-index.wxss
|    |         |-index.wxml
|    |--testa // 其他 npm 包
|         |--package.json
|         |--lib
|         |    |--entry.js
|         |--node_modules
|              |--testb
|                   |--package.json
|                   |--main.js
|--pages
|--app.js
|--app.wxss
|--app.json
|--project.config.js

构建之后的结构:

|--node_modules
|--miniprogram_npm
|    |--testComp // 小程序 npm 包
|    |    |-index.js
|    |    |-index.json
|    |    |-index.wxss
|    |    |-index.wxml
|    |--testa // 其他 npm 包
|         |--index.js // 打包后的文件
|         |--miniprogram_npm
|              |--testb
|                   |--index.js // 打包后的文件
|                   |--index.js.map
|--pages
|--app.js
|--app.wxss
|--app.json
|--project.config.js

tips:打包生成的代码在同级目录下会生成 source map 文件,方便进行逆向调试。

开发第三方自定义组件

请查阅开发第三方自定义组件文档。

miniprogram_npm 组件寻址顺序

页面配置文件(如:pages/index/index.json)中使用 usingComponents

{"usingComponents": {"a": "a"}
}

其寻址顺序为

[// 先寻址相对路径"pages/index/a","pages/index/a/index",// 再尝试寻址 miniprogram_npm 下的组件"pages/index/miniprogram_npm/a","pages/index/miniprogram_npm/a/index",// 再尝试其父层级中的 miniprogram_npm 目录"pages/miniprogram_npm/a","pages/miniprogram_npm/a/index","miniprogram_npm/a","miniprogram_npm/a/index"
]

tips:建议对于组件是 a/index 和 a/a 的这种情况,或者同时存在 a 和 a/index 的情况,usingComponents 需要直接显示的写明 “a/index” 和 “a/a”,而不是只写 “a”。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • CCS10导入CCS3.3工程
  • 287. 寻找重复数(stl法)
  • 【机器学习】和【人工智能】在量子力学的应用及代码案例分析
  • Spring Cloud 八股文
  • 【笔记】物理化学绪论
  • 【video clips 专栏 2 -- videopad 视频拼接】
  • 【LLM】局域网内为容器服务启用HTTPS
  • Spring中Bean的相关注解
  • ROM修改进阶教程------如何修改固件 线刷转卡刷 卡刷转线刷 操作中的一些注意事项
  • C++20中头文件bit的使用
  • k8s的环境配置
  • 【Linux】【Vim】Vim 基础
  • Python 数据分析— Pandas 基本操作(下)
  • 使用QT编写有图形界面的TCP局域网聊天室(app)
  • Excel怎么截图?快速捕捉工作表的多种方法
  • (三)从jvm层面了解线程的启动和停止
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • 【剑指offer】让抽象问题具体化
  • 08.Android之View事件问题
  • Angular Elements 及其运作原理
  • ESLint简单操作
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • JavaScript的使用你知道几种?(上)
  • Mysql数据库的条件查询语句
  • PaddlePaddle-GitHub的正确打开姿势
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 关于List、List?、ListObject的区别
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • gunicorn工作原理
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • ​​​​​​​开发面试“八股文”:助力还是阻力?
  • ​力扣解法汇总946-验证栈序列
  • (C语言)fread与fwrite详解
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (floyd+补集) poj 3275
  • (php伪随机数生成)[GWCTF 2019]枯燥的抽奖
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (回溯) LeetCode 131. 分割回文串
  • (回溯) LeetCode 78. 子集
  • (亲测有效)推荐2024最新的免费漫画软件app,无广告,聚合全网资源!
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (自用)交互协议设计——protobuf序列化
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .NET C# 操作Neo4j图数据库
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .NET 材料检测系统崩溃分析
  • .NET 的程序集加载上下文
  • .net 中viewstate的原理和使用
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • @RequestMapping-占位符映射
  • @value 静态变量_Python彻底搞懂:变量、对象、赋值、引用、拷贝