1.項目目錄
- build:webpack打包用(開發環境、發布環境)
- example:開發環境的模板頁
- lib:打包好的文件夾(用於發布到npm上)
- src:想要封裝的公共組件
- .babelrc:處理es6語法
- package.json:打包的依賴文件,管理項目模塊包
開發環境配置(webpack.dev.config.js)
const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: path.join(__dirname, '../example/main.js'),
devtool: 'cheap-module-eval-source-map',
output: {
path: path.join(__dirname, '../dist'),
filename: 'bundle.js'
},
plugins: [ // 插件
new htmlWebpackPlugin({
template: path.join(__dirname, '../example/index.html'),
filename: 'index.html'
})
],
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }, // 如果想要啟用 CSS 模塊化,可以為 css-loader 添加 modules 參數即可
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
{ test: /\.(jpg|png|gif|bmp|jpeg)$/, use: 'url-loader?limit=5000' },
{ test: /\.(ttf|eot|svg|woff|woff2)$/, use: 'url-loader?limit=5000' },
{ test: /\.jsx?$/, use: 'babel-loader', exclude: /node_modules/ }
]
}
}
打包環境配置(webpack.pub.config.js)
const path = require('path')
// 導入每次刪除文件夾的插件
const cleanWebpackPlugin = require('clean-webpack-plugin')
const webpack = require('webpack')
// 導入抽取CSS的插件
const ExtractTextPlugin = require("extract-text-webpack-plugin")
// 導入壓縮CSS的插件
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
entry: path.join(__dirname, '../src/index.js'),
devtool: 'cheap-module-source-map',
output: {
path: path.join(__dirname, '../lib'),
filename: 'index.js',
libraryTarget: 'umd', //發布組件專用
library: 'ReactCmp',
},
plugins: [ // 插件
new cleanWebpackPlugin(['./lib']),
new webpack.optimize.UglifyJsPlugin({
compress: { // 配置壓縮選項
warnings: false // 移除警告
}
}),
new ExtractTextPlugin("css/styles.css"), // 抽取CSS文件
new OptimizeCssAssetsPlugin()// 壓縮CSS的插件
],
module: {
rules: [
{
test: /\.css$/, use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader",
publicPath: '../' // 指定抽取的時候,自動為我們的路徑加上 ../ 前綴
})
},
{
test: /\.scss$/, use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'sass-loader'],
publicPath: '../' // 指定抽取的時候,自動為我們的路徑加上 ../ 前綴
})
},
{ test: /\.(jpg|png|gif|bmp|jpeg)$/, use: 'url-loader?limit=5000&name=images/[hash:8]-[name].[ext]' },
{ test: /\.(ttf|eot|svg|woff|woff2)$/, use: 'url-loader?limit=5000&name=images/[hash:8]-[name].[ext]' },
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
]
}
}
組件
// button.js 封裝的button組件
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default class Button extends Component {
constructor(props) {
super(props)
}
static propTypes = {
/**
* @title 樣式定義
* @description 通過CSS定義按鈕的樣式
*/
style: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number,
background: PropTypes.string,
padding: PropTypes.string,
}),
};
static defaultProps = {
style: {
color: '#fff',
background: 'green',
padding: '4px',
},
};
render() {
const style = this.props.style;
return (
<button style={style}>{this.props.children}</button>
);
}
}
// index.js輸出文件
import React from 'react';
import RCmp from './app';
import Button from './button';
import Photo from './photo';
import './app.scss';
RCmp.Button = Button;
RCmp.Photo = Photo;
export default RCmp;
export {
Button,
Photo,
RCmp,
}
實時調試
npm run dev
package.json
{
"name": "react-cmp",
"version": "0.0.4",
"description": "初始化開發react組件",
"main": "lib/index.js",
"files": [
"build",
"example",
"src"
],
"repository": {
"type": "git",
"url": "git+https://github.com/lydxwj/react-cmp.git"
},
"homepage": "https://github.com/lydxwj/react-cmp",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --config ./build/webpack.dev.config.js --open --port 3000 --hot",
"pub": "webpack --config ./build/webpack.pub.config.js",
"prepublish": "npm run pub"
},
"keywords": [ "react", "component", "react-cmp" ],
"author": "author",
"license": "MIT",
"dependencies": {
"prop-types": "^15.6.0",
"react": "^16.1.1",
"react-dom": "^16.1.1"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-import": "^1.6.2",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"clean-webpack-plugin": "^0.1.17",
"css-loader": "^0.28.7",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.5",
"html-webpack-plugin": "^2.30.1",
"node-sass": "^4.6.0",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"sass-loader": "^6.0.6",
"style-loader": "^0.19.0",
"url-loader": "^0.6.2",
"webpack": "^3.8.1",
"webpack-dev-server": "^2.9.4"
}
}
package.json 簡要介紹
- name - 包名;
- version - 包的版本號;
- description - 包的描述;
- homepage - 包的官網 url;
- author - 包的作者姓名;
- contributors - 包的其他貢獻者姓名;
- dependencies - 依賴包列表。如果依賴包沒有安裝,npm 會自動將依賴包安裝在 node_module 目錄下;
- repository - 包代碼存放的地方的類型,可以是 git 或 svn,git 可在 Github 上;
- main - main 字段指定了程序的主入口文件,require('moduleName') 就會加載這個文件。這個字段的默認值是模塊根目錄下面的 index.js;
- keywords - 關鍵字;
發布
新建一個文件,名為.npmignore,是不需要發布到npm的文件和文件夾,規則和.gitignore一樣。如果你的項目底下有.gitignore但是沒有.npmignore,那么會使用.gitignore里面的配置。
npm run pub
引入
iimport React from 'react';
import PropTypes from 'prop-types';
import {
modal
} from 'math_manage'
import AutoSuggest from 'react-tiny-autosuggest';
import MyApp,{Button,Photo,} from 'react-cmp-master';
class App extends React.Component {
static defaultProps = {}
static propTypes = {}
constructor(props) {
super(props);
}
componentWillMount() {
document.title = "1666";
console.log(modal);
}
render() {
const suggestions = ['foo', 'bar'];
const handleSelect = selection => {console.log(selection)};
let input;
const handleSubmit = () => console.log(input.value);
return (
<div>
<AutoSuggest
suggestions = {suggestions}
onSelect = {handleSelect}
placeholder = "whatever..."
/>
<MyApp text='Hello react組件'/>
<Button/>
<Photo src={'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2198746125,2255961738&fm=27&gp=0.jpg'}/>
</div>
)
}
}
export default App;
版本管理
分為三個版本
- 主版本號(A):當你做了不兼容的 API 修改,0表示處於開發階段;
- 次版本號(B):當你做了向下兼容的功能性新增;
- 修訂號(C):當你做了向下兼容的問題修正。
~允許小版本迭代
- 如果有缺省值,缺省部分任意迭代;
- 如果沒有缺省值,只允許補丁即修訂號(Patch)的迭代
eg.:
- ~1.2.3:>=1.2.3 <1.3.0
- ~1.2:>=1.2.0 < 1.3.0(相當於1.2.x)
- ~1:>=1.0.0 <2.0.0(相當於1.x)
- ~0.2.3:>=0.2.3 <0.3.0
- ~0.2:>=0.2.0 <0.3.0(相當於0.2.x)
- ~0:>=0.0.0 <1.0.0(相當於0.x)
^允許大版本迭代
- 允許從左到右的第一段不為0那一版本位+1迭代(左閉右開);
如果有缺省值,且缺省值之前沒有不為0的版本位,則允許缺省值的前一位版本+1迭代
eg.: - ^1.2.3:>=1.2.3 <2.0.0
- ^0.2.3:>=0.2.3 <0.3.0
- ^0.0.3:>=0.0.3 <0.0.4
- ^1.2.x:>=1.2.0 <2.0.0
- ^0.0.x:>=0.0.0 <0.1.0
- ^0.0:>=0.0.0 <0.1.0
- ^1.x:>=1.0.0 <2.0.0
- ^0.x:>=0.0.0 <1.0.0
每個npm包都有一個package.json,如果要發布包的話,package.json里面的version字段就是決定發包的版本號了。
version字段是這樣一個結構: ‘0.0.1’,是有三位的版本號。分別是對應的version里面的:major, minor, patch。
也就是說當發布大版本的時候會升級為 1.0.0,小版本是0.1.0,一些小修復是0.0.2。
鎖定(控制)版本
package-lock.json或是yarn.lock。
在npm的版本>=5.1的時候,package-lock.json文件是自動打開的,意味着會自動生成,
package-lock.json(官方文檔)可以理解為/node_modules文件夾內容的json映射,並能夠感知npm的安裝/升級/卸載的操作。可以保證在不同的環境下安裝的包版本保持一致。聽上去很不錯哈,實際使用中,大部分它的表現確實不錯,可是如上述問題:我手動修改了package.json文件內依賴的版本,package-lock.json就沒那么聰明(至少目前是,未來會不會變聰明就不可知了),且不會變化。
如果你真的想保證你的包版本在各個環境都是一樣的話,請修改下package.json中的依賴,去掉默認前面的^,當然這樣的話,你就沒法自動享受依賴包小版本的修復了,問題來了,在什么情況下選擇哪一種呢?
在依賴包嚴格按照版本規范來開發的,你可以使用^來享受包的最新功能和修復。這也是推薦的。
在你不可知或已知依賴包不是那么規范的情況下,或許它在一個小版本(patch)做出不兼容更改(不兼容更改在beta等先行版本中一定[墨菲定律]會發生),那么這個時候,你應該把這個依賴包的版本在package.json上鎖住版本,而不應該把它交給package-lock.json來處理
記住一點,絕對不要在生成環境下使用beta等先行版本依賴包,因為如果那是你的私有項目,它會在未來的某一刻坑害了你,如果這是你的共有項目,那么,它一定會在未來的某一刻對你的所有用戶做出致命的坑害行為!(beta包就是不負責任的流氓包,玩家爽就好 )
- 最后:rm -rf node_modules/ && npm install大法在你使用package-lock的情況下,請更換為:rm -rf node_modules && rm -rf package-lock.json && npm install。