原文地址:https://www.douyacun.com/article/0fbb7c346c25a7829cfe11008bb62783
已经成功发布 react 天气组件 , 以及 npm publis react demo 简单实例,此文就是基于此demo
完整代码已经发到 Github: https://github.com/douyacun/npm-publish-react-component
误区:
概要:
体验:
git clone https://github.com/douyacun/npm-publish-react-component.git
npm install
npm start
目录:
.
├── LICENSE
├── babel.config.json
├── example
│ ├── index.html
│ ├── index.js
│ └── webpack.config.js
├── lib
│ ├── index.js
│ └── index.js.LICENSE.txt
├── package.json
├── src
│ ├── index.css
│ └── index.js
└── webpack.config.js
git init初始化,指定origin仓库,接下来npm会帮忙初始化号git相关的字段
npm init
初始化 package.json,里面的信息都填写一下,这是搜到这个包的关键,尤其是是keywords
安装一下react打包需要的插件, react/babel/webpack
npm install react react-dom --save
npm install @babel/core @babel/preset-env @babel/preset-react babel-loader --save-dev
npm install webpack webpack-cli webpack-dev-server --save-dev
babel.config.json
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
完整 的 package.json
{
"name": "npm-publish-react-component", // 重要! npm install <?> 包名,全局唯一
"version": "1.0.0", // 版本号,每次发布累加一
"description": "npm发包流程", // seo 三剑客
"main": "lib/index.js",// 重要!import Demo from "npm-publish-react-component" 就是引入main指定的文件~
"keywords": [
"npm publish",
"npm发布",
"react组件",
"react component"
],// seo 三剑客
"scripts": {
"start": "webpack serve --config example/webpack.config.js",
"build": "webpack"
},
"author": "douyacun",
"license": "MIT",
"dependencies": {
"react": "^17.0.1",
"react-dom": "^17.0.1"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "^7.12.10",
"babel-loader": "^8.2.2",
"css-loader": "^5.0.1",
"html-webpack-plugin": "^4.5.1",
"style-loader": "^2.0.0",
"webpack": "^5.11.1",
"webpack-cli": "^4.3.1",
"webpack-dev-server": "^3.11.1"
},
"directories": {
"example": "example",
"lib": "lib"
},
"repository": {
"type": "git",
"url": "git+https://github.com/douyacun/npm-publish-react-component.git"
},
"bugs": {
"url": "https://github.com/douyacun/npm-publish-react-component/issues"
},
"homepage": "https://github.com/douyacun/npm-publish-react-component#readme"
}
entry: './src/index.js', // 打包哪个文件
package.json
main 文件output: {
path: path.join(__dirname, '../lib/'), // 输出到哪
filename: 'index.js', // 输出的文件名字
libraryTarget: 'umd', // 重要!
}
"main": "lib/index.js"
这里罗列一下各个选项的含义:
var MyLibrary = _entry_return_;
// 在一个单独的 script……
MyLibrary.doSomething();
this["MyLibrary"] = _entry_return_;
// 在一个单独的 script……
this.MyLibrary.doSomething();
MyLibrary.doSomething(); // 如果 this 是 window
window["MyLibrary"] = _entry_return_;
window.MyLibrary.doSomething();
global
对象的这个属性下。一般用在node环境中global["MyLibrary"] = _entry_return_;
global.MyLibrary.doSomething();
exports["MyLibrary"] = _entry_return_;
require("MyLibrary").doSomething();
define([], function() {
return _entry_return_; // 此模块返回值,是入口 chunk 返回的值
});
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else {
var a = factory();
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
}
})(typeof self !== 'undefined' ? self : this, function() {
return _entry_return_; // 此模块返回值,是入口 chunk 返回的值
});
完整 webpack.config.json
const path = require('path');
module.exports = {
entry: './src/index.js', // 打包哪个文件
output: {
path: path.join(__dirname, '../lib/'), // 输出到哪
filename: 'index.js', // 输出的文件名字
libraryTarget: 'commonjs2', // 重要!
},
externals: { // 重要!Minified React error #321 https://github.com/facebook/react/issues/16029
react: {
commonjs: 'react',
commonjs2: 'react',
amd: 'react',
root: 'React',
},
'react-dom': {
commonjs: 'react-dom',
commonjs2: 'react-dom',
amd: 'react-dom',
root: 'ReactDOM',
},
},
resolve: {
extensions: ['.js', '.jsx']
},
mode: "production",
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"] // style-loader 会把css与js文件打包在一个文件中
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: ["babel-loader"]
}
]
},
performance: {
hints: "warning", // 枚举
hints: "error", // 性能提示中抛出错误
hints: false, // 关闭性能提示
maxAssetSize: 200000, // 整数类型(以字节为单位)
maxEntrypointSize: 400000, // 整数类型(以字节为单位)
assetFilter: function (assetFilename) {
// 提供资源文件名的断言函数
return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
}
}
}
服务端渲染:
const path = require('path');
const TerserJSPlugin = require('terser-webpack-plugin');
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
output: {
path: path.join(__dirname, '../lib/ssr/'),
filename: 'index.js',
libraryTarget: 'commonjs2',
},
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
plugins: [new ExtractCssChunks({filename: 'index.css',})],
module: {
rules: [
{
test: /\.css$/,
use: [ExtractCssChunks.loader, "css-loader"]
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: ["babel-loader"]
}
]
}
}
其他配置复用上面的配置,使用了2个插件将css单独出一个文件出来,否则服务端渲染时会报:document is not defined
,
这样引入组件时就需要单独引入js文件和css文件:
import React from 'react';
import ReactDOM from 'react-dom';
import Weather from 'react-tencent-weather/lib/ssr/index.js';
import 'react-tencent-weather/lib/ssr/index.css';
ReactDOM.render(
<div><Weather province="上海" city="上海" /></div>,
document.getElementById('root')
)
1. 注册npm账号
去 https://www.npmjs.com/ 注册一个账号就ok了
在此注意!: npm是否使用淘宝或其他镜像代理
npm config list
如果使用了的话,注视掉
vim .npmrc
//registry=https://registry.npm.taobao.org/
使用npm build打包一下出来js文件,npm包发布的是webpack babel编译后的文件~
npm build
打包完成后肯定要测试一下的对吧
2. 本地测试打包文件 npm link
npm link
会把当前目录 软链 到全局路径下
➜ npm-publish-react-component git:(master) ✗ npm link
npm notice created a lockfile as package-lock.json. You should commit this file.
removed 262 packages in 3.534s
52 packages are looking for funding
run `npm fund` for details
/Users/liuning/.nvm/versions/node/v12.19.0/lib/node_modules/npm-publish-react-component -> /Users/liuning/Documents/github/npm-publish-react-component
npm link npm-publish-react-component
将 全局路径下的 npm-publish-react-component
包软链到当前目录下的 node_modules
➜ npm-publish-react-component git:(master) ✗ npm link npm-publish-react-component
/Users/liuning/Documents/github/npm-publish-react-component/node_modules/npm-publish-react-component -> /Users/liuning/.nvm/versions/node/v12.19.0/lib/node_modules/npm-publish-react-component -> /Users/liuning/Documents/github/npm-publish-react-component
我们就可以直接在example/index.js中直接import使用
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from 'npm-publish-react-component';
ReactDOM.render(
<div><Demo name="douyacun"/></div>,
document.getElementById('root')
)
删除 package-lock.json
npm start
要确保 使用的webpack使用的配置文件是测试的配置,最好区分 测试/正式 环境
1. 引入包报错: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.
react.development.js:220 Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
这个就是webpack没有指定: libraryTarget
导致,详细在看一下上面我们罗列的选项
2. 引入包报错:Uncaught ReferenceError: module is not defined
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from 'douyacun-react-demo';
ReactDOM.render(
<div><Demo name="douyacun"/></div>,
document.getElementById('root')
)
报错:
3. npm run build 报错 Cannot find module 'pkg-dir'
这个是因为: npm link 在 node_module 创建软链导致的
解决方案:
npm install
4. import react组件时报错:Uncaught Error: Minified React error #321
如果react组件中使用了hook,useState/useEffect 就会导致这个问题,react官方给出的解决方案:https://github.com/facebook/react/issues/16029
原因是因为两次引入了react
➜ npm-publish-react-component git:(master) ✗ npm run build
> npm-publish-react-component@1.0.0 build /Users/liuning/Documents/github/npm-publish-react-component
> webpack
{ javascriptModule: false }
asset index.js 8.28 KiB [compared for emit] [minimized] (name: main) 1 related asset
runtime modules 931 bytes 4 modules
orphan modules 326 bytes [orphan] 1 module
cacheable modules 19.6 KiB
modules by path ./node_modules/ 16.8 KiB
modules by path ./node_modules/react/ 6.48 KiB
./node_modules/react/index.js 190 bytes [built] [code generated]
./node_modules/react/cjs/react.production.min.js 6.3 KiB [built] [code generated] <----- 这里将 react 也打包进去了~
./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js 6.67 KiB [built] [code generated]
./node_modules/object-assign/index.js 2.06 KiB [built] [code generated]
./node_modules/css-loader/dist/runtime/api.js 1.57 KiB [built] [code generated]
modules by path ./src/ 2.85 KiB
./src/index.js + 1 modules 2.49 KiB [built] [code generated]
./node_modules/css-loader/dist/cjs.js!./src/index.css 368 bytes [built] [code generated]
webpack 5.12.2 compiled successfully in 1092 ms
解决方法:
externals: { // 重要!Minified React error #321 https://github.com/facebook/react/issues/16029
react: {
commonjs: 'react',
commonjs2: 'react',
amd: 'react',
root: 'React',
},
'react-dom': {
commonjs: 'react-dom',
commonjs2: 'react-dom',
amd: 'react-dom',
root: 'ReactDOM',
},
}