这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战
一.npm 是什么?
npm 是世界上最大的软件注册中心。世界各地的开源开发者都使用 npm 来共享包,许多组织也使用 npm 来管理私有开发[1]。
1. npm 的组成
官方文档上介绍到,由三部分组成
- 官方网站(可以查询各种包)
- 命令行工具 (CLI)
- 注册管理中心
2.使用 npm 的好处
- 方便下载各种工具
- 使用 npx 无需下载即可运行包。
- 在任何地方与任何 npm 用户共享代码。
- 寻找其他正在处理类似问题和项目的开发人员。
二.开始尝试
- 首先挖掘需求吧,什么情况下需要一个 npm 包呢?
- 比如,在开发过程中,经常需要的使用的一些代码,我们就可以把它们聚合起来,通过维护一个 npm 包,在不同项目中引入即可。
- 其实已经准备好了,可以看这几篇:
- 这些都可以做成一个 npm 包,独立使用。
- 当然,主要原因还是 本文第一句
三.编写代码
1.初始化项目
- yarn init 生成一个package.json文件
{
"name": "flibrary",
"version": "1.0.0",
"description": "聚合各种函数的 JS 工具包,具体看readme",
"main": "index.js",
"repository": "",
"author": "",
"license": "MIT"
}
- 需要注意的就是
"main": "index.js",
- 这是打包输出文件的入口
2.新建一个index.js
- 复制我们看到的代码 前端常用js代码汇总
- 结果如下
// index.js
export const getAllQueryString = (url) => {
const r = {};
const _url = url || window.location.href;
if (_url.split('?')[1]) {
let str = _url.split('?')[1];
str = str.split('&');
str.forEach((item) => {
const key = item.split('=')[0];
const val = item.split('=')[1];
r[key] = decodeURIComponent(val);
});
}
return r;
}
...
- 目前的文件目录
三.打包压缩
1.目前主流的打包工具有两个: rollup 和 webpack
- rollup 最早支持 Tree-shaking ,主要用来打包类库
- webpack 主要用来开发应用。但随着发展,该有的功能几乎都有了
- 所以其实差别不是很大,用任意一个压缩打包代码都可以,看个人喜好
2.为什么要打包压缩
-
需要babel编译,解决各种兼容问题
-
压缩代码,减少文件体积
-
方便对代码进行一些统一处理
-
所以打包过程实际就是一个输入和输出的过程
-
需要注意的是:
- 在导入模块的选择上,我们可以使用 require 或者 import
- require是CommonJs的语法(AMD规范引入方式),CommonJs的模块是对象。
- require 是运行时加载整个模块(即模块中所有方法),生成一个对象,再从对象上读取它的方法(只有运行时才能得到这个对象,不能在编译时做到静态化)。通过 require 引入基础数据类型时,属于复制该变量。通过 require 引入复杂数据类型时,数据浅拷贝该对象。
- import 命令会被 JavaScript 引擎静态分析,先于模块内的其他模块执行,具有提升效果。会提升到模块的头部,import导出的类型看定义的对象,定义number导出就是number,定义字符串就是字符串,你定义对象导出的就是对象。
- 不同的导入引用方式,会有不同的打包效果
- export和import可以位于模块中的任何位置,但是必须是在模块顶层,如果在其他作用域内,会报错。
2. rollup 压缩打包
(1).安装
npm install rollup
(2).直接使用rollup命令
rollup
由于不加任何参数,打印出rollup的使用说明,和运行 rollup --help 或 rollup -h 的效果一样。
(3).打包进行输入输出
- 既然打包过程就是一个输入和输出的过程,那么至少要指定输入的文件,和输出的格式
rollup index.js -f cjs
-f 选项(--output.format 的缩写)指定了所创建 bundle 的类型——这里是 CommonJS(在 Node.js 中运行)。
- 其他参数:
- amd – 异步模块定义,用于像RequireJS这样的模块加载器
- cjs – CommonJS,适用于 Node 和 Browserify/Webpack
- esm – 将软件包保存为 ES 模块文件,在现代浏览器中可以通过
<script type=module>标签引入 - iife – 一个自动执行的功能,适合作为
<script>标签。(如果要为应用程序创建一个捆绑包,您可能想要使用它,因为它会使文件大小变小。) - umd – 通用模块定义,以amd,cjs 和 iife 为一体
- system - SystemJS 加载器格式
- 备注:如果直接使用这个命令打包本次的代码,会报错
[!] Error: Unexpected keyword 'export'
- 既然能指定输出的格式,那么肯定可以指定输出的文件名
rollup index.js -o bundle.js -f cjs
- 如果需要开启各种功能,代码压缩,
sourcemap,babel等,直接使用命令行可能就不方便了,所以就需要打包的配置文件,通过指定各种配置文件,来输出想要的结果
rollup -c rollup.config.js
- 注意:如果同时有命令行选项和配置文件,命令行选项将会覆盖配置文件中的选项
(4).rollup.config.js
import resolve from 'rollup-plugin-node-resolve'; // 支持导入node的包
import commonjs from 'rollup-plugin-commonjs'; // 支持导入commonjs
import babel from 'rollup-plugin-babel'; // 编译代码
import { terser } from 'rollup-plugin-terser'; // 代码压缩,去除注释
import { eslint } from 'rollup-plugin-eslint';
export default [
{
input: './index.js',
output: {
name: '',
file: 'bundle.js',
format: 'umd',
sourcemap: true,
// 这里需要注意,设置打包压缩后的文件开头,会被 terser 插件去除
banner: '/*eslint-disable*/',
},
plugins: [
resolve({
browser: true,
}), // 这样 Rollup 能找到 `ms`
commonjs(), // 这样 Rollup 能转换 `ms` 为一个ES模块
eslint({
throwOnError: true,
throwOnWarning: true,
include: ['main.js'],
exclude: ['node_modules/**'],
}),
babel({
exclude: 'node_modules/**', // 防止打包node_modules下的文件
runtimeHelpers: true, // 使plugin-transform-runtime生效
}),
terser()
],
},
];
(4).package.json 添加脚本
"scripts": {
"build": "rollup -c ./rollup.config.js",
"test": "echo \"Error: no test specified\" && exit 1",
"prepublish": "npm run build"
},
- 这样直接执行
npm run build就能打包 prepublish是再执行npm publish(发布前)自动再执行npm run build一次
3.webpack 打包
- 用完rollup后,同时也用webpack试试
//webpack.config.js
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
entry: './main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack.bundle.js'
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},
};
- 执行命令:
npx webpack --config webpack.config.js
四.调试
1.npm link
(1).在需要打包成npm的项目目录内输入npm link生成一个链接,从全局的node/v14.8.0/lib链接到本地正在开发的这个项目上
/Users/.nvm/versions/node/v14.8.0/lib/node_modules/flibrary -> /Users/event/flibrary
(2).链接到全局之后,就可以在开发的时候调试了。在需要引用这个包的环境内使用npm link flibrary(上面生成链接的包的名字)
链接成功,就可以直接引用了
import { getAllQueryString } from "flibrary"
node_modules中会出现一个链接的文件
2.npm unlink
使用完之后记得unlink就可以了,操作和npm link一样
3.断点调试
五.发布
1. 到 npmjs上注册一个账号
2. npm adduser
输入用户名,密码,邮箱即可登入成功
3. 可以用npm whoami进行查看是否登录成功
4. npm publish
- 注意:npm publish 的时候会把项目目录里面所有的文件都publish到npm仓库中。
- 发布指定文件方法:
- 一:使用 .gitignore,在git代码管理和 npm publish 都会被忽略
- 二:使用 .npmignore: .npmignore 写法跟 .gitignore 完全一样。若同时使用了 .npmignore和 .gitignore,只有 .npmignore 会生效,在npm发布上优先级比.gitignore 更高。
- 三:使用 package.json 的 files 字段选择发布哪些文件直接在 package.json 中 files 字段设置发布哪些文件或目录。这个优先级高于 .npmignore 和 .gitignore。
PS:选择哪种方法,根据自己的需求而定。
不过注意下发布的版本,在package.json里面,也可以用命令行 npm publish --tag指定