npm构建并发布一个包

一直想构建一个npm包并发布到社区。这次趁着百日计划把这项工作好好落实了。以下是整个流程的记录。

参考1: 从零开始发布一个React组件到npm
参考2: 基于webpack和ES6构建npm包
参考3: 怎么写一个React组件库

构建流程


1. 初始化工作

1.1 创建git仓库

为了方便版本控制,最好创建一个git仓库来管理我们的代码。这里略。

1.2 添加npm用户

在npm官网注册好用户之后,就可以使用这个账号来登陆:

$ npm set init.author.name "Your Name"
$ npm set init.author.email "you@example.com"
$ npm set init.author.url "http://yourblog.com"

$ npm adduser

1.3 npm项目初始化

$ npm init

填写好项目的基本信息之后初始化工作就结束了。


2. 脚手架搭建

2.1 安装必要构建包

这里可以参考我之前的一篇博文: Yarn + webpack 构建项目

  1. 安装React相关组件
npm i react react-dom -D
  1. 安装webpack相关
npm i webpack webpack-cli webpack-dev-server html-webpack-plugin style-loader css-loader babel-core babel-loader babel-preset-env babel-preset-react babel-loader@7 -D

  1. 相关配置
  • webpack.config.js
    幸运的是,webpack到4.0以后就实现了几乎“零配置”的开箱即用,这里对webpack不需要做太多配置工作,在项目根目录下创建这个文件即可。如果你的组件构建需要用到一些基于webpack的工具,那需要自行解决。
/*** webpack.config.js ***/
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const htmlWebpackPlugin = new HtmlWebpackPlugin({
 template: path.join(__dirname, "examples/src/index.html"),
 filename: "./index.html"
});
module.exports = {
 entry: path.join(__dirname, "examples/src/index.js"),
 module: {
   rules: [{
     test: /\.(js|jsx)$/,
   use: "babel-loader",
   exclude: /node_modules/
 },{
   test: /\.css$/,
   use: ["style-loader", "css-loader"]
 }]
},
 plugins: [htmlWebpackPlugin],
 resolve: {
   extensions: [".js", ".jsx"]
 },
 devServer: {
   port: 3001
}};
  • package.json
    配置一下启动命令脚本
 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1",
   "start": "webpack-dev-server --mode development"
 },

2.2 配置开发环境

1. eslint配置(不是必要)

自动生成.eslintrc.js文件并安装相关依赖(可根据自己喜好选择代码规范)



$ npm install eslint -D
$ npm install eslint -g # 全局安装ESLint
// 安装eslint相关
$ npm i eslint-plugin-html babel-eslint -D
$ eslint --init


? How would you like to configure ESLint? Use a popular style guide
? Which style guide do you want to follow? Standard
? What format do you want your config file to be in? JavaScript

添加.eslintignore文件忽略对输出目录的代码检测

dist/

2. babel 配置
创建..babelrc文件:

{
  "presets": ["env", "react"]
 }

2.3 整理项目目录结构

├── examples // 示例代码存放目录
│  └── src
├── node_modules
├── package.json
└── src // 组件源代码和样式存放目录

3. 简单组件示例

下面我将创建一个非常简单的组件以作为示例

  • src/index.js
/*** src/index.js  ***/
import React from 'react';
import './styles.css';
const MyComponent = () => (
 <h1>Hello from My Component</h1>
);
export default MyComponent;
  • src/styles.css
/*** src/styles.css ***/
h1 {
 color: red;
}
  • examples/src/index.html
<!-- examples/src/index.html -->
<html>
<head>
 <title>My Component Demo</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
</head>
<body>
 <noscript>
 You need to enable JavaScript to run this app.
 </noscript>
 <div id="root"></div>
</body>
</html>
  • examples/src/index.js
/*** examples/src/index.js ***/
import React from 'react';
import { render} from 'react-dom';
import MyComponent from '../../src';
const App = () => (
 <MyComponent />
);
render(<App />, document.getElementById("root"));

4. 测试和打包(未完成)

接下来运行 demo

npm start

启动完成后打开浏览器输入 http://localhost:3001,你将会在页面上看到你写的组件,你可以修改你的代码并保存,页面将会自动刷新,我们的开发环境已经处于监控模式。

确认无误之后,进入下一步工作。

1. 首先需要安装 babel cli

npm i babel-cli -D

现在我们添加 transpile 脚本,以便使用 Babel 编译我们的源代码,同时拷贝一些静态文件 (如:css 文件) 到目标打包目录 dist 下。

# package.json
...
 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1",
   "start": "webpack-dev-server --mode development",
   "transpile": "babel src -d dist --copy-files"
 },
...

2. 尝试编译

npm run transpile

现在在我们项目根目录下面会有一个 dist 目录,包含了 index.js 的编译版本,和拷贝的样式文件 styles.css, 这些文件是用户可以直接 可以 import 到他们项目的文件,接下来我们再在我们的工作流中添加一个脚本 prepublishOnly , 这个脚本会在每次我们需要发布我们的组件到 npm 上去的时候会自动执行,他能确保我们每次发布上去的代码都是最新代码编译的。

5. 发布以及善后

编译完成后,并且通过测试,接下来就是发布了。
发布之前,还有一点小小的工作需要处理。我们需要告诉用户在用户我们的组件的时候对于 React 版本的要求,peerDependency 能够很好的表达这个信息,同时在我们的发布的组件包中不会包含 react , 这样也减小了包的大小,更加重要是可以避免在用户的项目中存在多个 react 版本,更新 package.json 如下:

...
 "peerDependencies": {
   "react": "^16.3.0",
   "react-dom": "^16.3.0"
 },
...

最后让我们在项目的根目录下添加.npmignore 文件,告诉 npm,我们项目中哪些文件和文件夹是在发布的包中被忽略掉的

# .npmignore 
src
examples
.babelrc
.gitignore
webpack.config.js

发布我们的组件到 npm 上

npm publish

这时你去浏览器的 npm 主页,应该就能看到我们刚才发布的新包了。

6. GitHub Pages 上发布一个在线 demo

在 GitHub Pages 托管在线 Demo 是免费的,需要使用 webpack 来构建我们的生产环境版本,然后发布到 GitHub 仓库指定的分支上去,接下来让我们自动化完成这些吧!

首先,我们需要借助一个帮助维护特性分支的包,我们还没有对我们的项目添加 git 代码版本控制,稍等片刻

 npm i gh-pages -D

然后在 package.json 中添加三个脚本

{
 "name": "my-component",
 "version": "1.0.0",
 "description": "",
 "main": "dist/index.js",
 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1",
   "start": "webpack-dev-server --mode development",
   "transpile": "babel src -d dist --copy-files",
   "prepublishOnly": "npm run transpile",
   "build": "webpack --mode production",
   "deploy": "gh-pages -d examples/dist",
   "publish-demo": "npm run build && npm run deploy"
 },
 "author": "",
 "license": "ISC",
 "peerDependencies": {
   "react": "^16.3.0",
   "react-dom": "^16.3.0"
 },
 "devDependencies": {
   "babel-cli": "^6.26.0",
   "babel-core": "^6.26.0",
   "babel-loader": "^7.1.4",
   "babel-preset-env": "^1.6.1",
   "babel-preset-react": "^6.24.1",
   "css-loader": "^0.28.11",
   "gh-pages": "^1.1.0",
   "html-webpack-plugin": "^3.2.0",
   "react": "^16.3.2",
   "react-dom": "^16.3.2",
   "style-loader": "^0.20.3",
   "webpack": "^4.5.0",
   "webpack-cli": "^2.0.14",
   "webpack-dev-server": "^3.1.3"
 }
}

build 脚本目的是用 webpack 帮我们构建一个 boundled, 和压缩生产环境代码,这里我们需要告诉 webpack 哪个文件是我们项目输出的结果

/*** webpack.config.js ***/
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const htmlWebpackPlugin = new HtmlWebpackPlugin({
 template: path.join(__dirname, "examples/src/index.html"),
 filename: "./index.html"
});
module.exports = {
 entry: path.join(__dirname, "examples/src/index.js"),
 output: {
   path: path.join(__dirname, "examples/dist"),
   filename: "bundle.js"
 },
 module: {
   rules: [{
     test: /\.(js|jsx)$/,
     use: "babel-loader",
     exclude: /node_modules/
   },{
     test: /\.css$/,
     use: ["style-loader", "css-loader"]
   }]
 },
 plugins: [htmlWebpackPlugin],
 resolve: {
   extensions: [".js", ".jsx"]
 },
 devServer: {
   port: 3001
 }
};

来,试一试

npm run build

你会发现生成版本的代码已经打包到了 examples/dist
现在我们的本地和远程的仓库都已经创建并连接上了,准备将 demo 发布到托管环境了,这时,首先需要去这个项目的仓库中为它新建一个 gh-pages 的分支,deploy 脚本就是为了帮我们干这个事的

npm run deploy

点击设置连接到你的 github 仓库页面,然后滚动到 github pages 栏目,你将会看到你的 demo 在线连接地址,恭喜你 上线了!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,753评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,668评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,090评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,010评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,054评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,806评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,484评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,380评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,873评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,021评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,158评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,838评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,499评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,044评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,159评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,449评论 3 374
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,136评论 2 356

推荐阅读更多精彩内容

  • 1 Webpack 1.1 概念简介 1.1.1 WebPack是什么 1、一个打包工具 2、一个模块加载工具 3...
    Kevin_Junbaozi阅读 6,673评论 0 16
  • 写在前面的话 阅读本文之前,先看下面这个webpack的配置文件,如果每一项你都懂,那本文能带给你的收获也许就比较...
    不忘初心_9a16阅读 3,235评论 0 17
  • 无意中看到zhangwnag大佬分享的webpack教程感觉受益匪浅,特此分享以备自己日后查看,也希望更多的人看到...
    小小字符阅读 8,172评论 7 35
  • 又到周五了,每到这一天我都感到自己的心总是忐忑不安的,总感觉有什么不好的事情会发生一样。 放学回家后因为我有一些事...
    风中百合_2f65阅读 146评论 0 1
  • 我的妹妹快5岁了,她是一个活泼、可爱、乖巧,又有点淘气的孩子! 她有一双小巧玲珑的小眼睛,笑起来那双小眼睛似乎变成...
    张永昌阅读 170评论 0 0