zoukankan      html  css  js  c++  java
  • react组件化开发发布到npm

    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。
  • 相关阅读:
    centos配置WordPress(Apache+mysql+php)
    sublime text3配置Python2、Python3的编译环境
    Python3——字典
    Python3基础——函数
    Python3基础——递归
    Python3基础——字符串类型
    activiti会签直接写死人员
    delete执行速度优化
    C盘空间满了怎么办
    python运算符
  • 原文地址:https://www.cnblogs.com/Hsong/p/9938928.html
Copyright © 2011-2022 走看看