zoukankan      html  css  js  c++  java
  • 从 0 到 1 到完美,写一个 js 库、node 库、前端组件库

    之前讲了很多关于项目工程化、前端架构、前端构建等方面的技术,这次说说怎么写一个完美的第三方库。

    1. 选择合适的规范来写代码

    js 模块化的发展大致有这样一个过程 iife => commonjs/amd => es6,而在这几个规范中:

    • iifejs 原生支持,但一般不会直接使用这种规范写代码
    • amdrequirejs 定义的加载规范,但随着构建工具的出现,便一般不会用这种规范写代码
    • commonjsnode 的模块加载规范,一般会用这种规范写 node 程序
    • es6ECMAScript2015 定义的模块加载规范,但到目前为止,几乎所有的 js 运行环境都不支持,包括浏览器、node(包括 electronnw.js)、React Native 等

    针对原生不支持任何规范的运行环境程序(如浏览器、React Native),建议使用 es6 规范来写代码,然后由工具转换成原生 js 能够运行的。

    而针对 node 程序,可以直接用 commonjs 规范来写,也可由 es6 规范来写,然后用工具转化成 commonjs 规范。

    所以,总的来说,都可以使用 es6 规范来写代码,然后用工具转换成其他规范,而且 es6 的代码可以使用 tree-shaking 功能。

    参考:

    2. 选择合适的构建工具

    对于前端项目来说,因为有静态资源(如图片、字体等)加载与按需加载的需求,所以使用 webpack 是不二选择,但对于第三方库来说,其实还有更好的选择:rollup

    可以查看 webpack 之外的另一种选择:rollup 了解 webpack 与 rollup 之间各自的差异与优势。

    webpack 在打包成第三方库的时候只能导出 amd/commonjs/umd,而 rollup 能够导出 amd/commonjs/umd/es6。使用 rollup 导出 es6 模块,就可以在使用这个库的项目中构建时使用 tree-shaking 功能。

    对于有样式文件(csslessscss)、静态资源文件(图片、字体)的前端组件来说,可以使用 rollup-plugin-postcss 插件配合 rollup处理样式文件与静态资源文件。

    参考:

    3. 定好目录结构

    一般库项目的目录:

    |-- /                   # 项目根目录
        |-- src/            # 源代码目录
        |-- lib/(dist/)     # 发布文件目录
        
        |-- test/           # 测试文件目录
        |-- ...             # 更多其他目录

    如果是多包项目(一个项目里有多个 npm packages,比如 babel):

    |-- /                           # 项目根目录
        |-- packages/               # packages 目录   
            |-- pkg1/               # package1 目录
                |-- src/            # 源代码目录
                |-- lib/(dist/)     # 发布文件目录
            |-- pkg2/               # package2 目录
                |-- src/            # 源代码目录
                |-- lib/(dist/)     # 发布文件目录
                
            |-- ...

    后面会详细讲解多包项目。

    4. 搭建一个好的脚手架

    不管是应用项目还是第三方库项目,都需要搭建一个好的脚手架,来帮助我们更好的编写代码、构建项目等。

    可以查看 搭建自己的前端脚手架 了解一些基本的脚手架文件与工具。

    比如:

    详细的文件、工具与配置,参考 搭建自己的前端脚手架

    另外,针对开源的第三方库,还可以有:

    • LICENSE: 协议文件
    • CONTRIBUTING.md: 项目代码参与者
    • codecov.yml: 测试覆盖率配置文件
    • .githubgithub 上的一些自定义配置,比如 issue 模板、pr 模板等
    • /docs: 文档目录
    • /examples: 使用示例目录
    • /scripts: 脚本目录

    加上 rollup 的配置文件 rollup.config.js:

    rollup.config.js

    如果是 node 程序,把 es6 规范转化成 commonjs 规范:

    export default {
      input: 'src/index.js',
      output: {
        file: 'lib/index.js',
        format: 'cjs',
      },
    };

    如果是前端库,还需要转 es6+ 到 es5、导出不同规范的文件(es6/commonjs/amd/umd):

    import babel from 'rollup-plugin-babel';
    import postcss from 'rollup-plugin-postcss';
     
    export default [
      {
        file: 'lib/cjs.js',
        format: 'cjs',
      },
      {
        file: 'lib/m.js',
        format: 'esm',
      },
      {
        file: 'lib/umd.js',
        format: 'umd',
        name: 'Name',
      },
      {
        file: 'lib/amd.js',
        format: 'amd',
      },
    ].map(output => ({
      input: 'src/index.js',
      output,
      plugins: [
        babel({
          presets: ['@babel/preset-env'],
        }),
        postcss({ extract: !0 }), // 构建样式文件时需要这个插件
      ],
    }));

    .gitignore

    一般来说,我们并不希望把发布文件放到 git 的版本控制之中,而只是发布到仓库而已,所以:

    # .gitignore
     
    .DS_Store
    node_modules
    bower_components
    /coverage
    *.log
    .idea
    .vscode
    .eslintcache
    package-lock.json
     
    /lib                        # 把 lib 排除在外
    /packages/*/lib             # 多包项目

    package.json

    {
      ...
      # node 项目
      "main": "lib/index.js",
      
      # 前端项目
      "main": "lib/cjs.js",              # commonjs 规范文件
      "module": "lib/m.js",              # es6 规范文件
      "umd:main": "lib/umd.js",          # umd 规范文件
      "amd:main": "lib/amd.js",          # amd 规范文件
      
      "files": [                         # 发布时只发布 lib 目录下文件
        "lib"
      ],
      "scripts": {
        ...
        "build": "rollup -c",            # 构建发布文件
        "prepublishOnly": "npm run build",    # npm publish 之前先 npm run build
        "pretest": "npm run build",      # npm run test 之前先 npm run build
      },
      ...
    }

    在实际项目中,构建工具(如 webpack)会首先找这个包中的 module 字段对应的 es6 规范文件,并使用 tree-shaking;如果不存在,然后找 main 字段对应的文件。

    有些构建工具可能也会用 amd 规范文件与 umd 规范文件。

    参考:

    5. 构建多包项目

    如果一个项目很大,需要分割成多个 npm 包进行管理,但这些包仍然在一个项目里,并且这些包可能有相互依赖关系,这个时候就比较难以管理和开发了。

    为了方便的管理多包项目,lerna 便应运而生,babelcreate-react-appjestlila 等都是用 lerna 来管理多个包的。

    英文不好的童鞋,可以参考 使用lerna管理大型前端项目,了解 lerna 的一些基本用法。

    lerna 一般目录文件结构

    my-lerna-repo/
      package.json
      packages/
        package-1/
          package.json
        package-2/
          package.json

    安装 lerna,初始化项目

    # 安装
    npm i -g lerna
    # 初始化
    git init lerna-repo && cd lerna-repo
    lerna init
    # 初始化后的目录及文件
    lerna-repo/
      packages/
      package.json
      lerna.json

    配置文件 lerna.json

    {
      "version": "0.5.2",             # 当前版本号
      "packages": [
        "packages/*"
      ],
      "command": {
        "publish": {                  # 发布配置
          "ignoreChanges": [          # 哪些文件变动不会引发发布新版本
            "*.md",
            "*.json",
            "*.txt",
            "test/**",
            "example/**",
            "package.json"
          ]
        },
        "bootstrap": {
          "npmClient": "cnpm"         # lerna bootstrap 时使用哪个 npm 客户端
        }
      },
      "npmClientArgs": [              # npm 客户端 运行时的参数
        "--no-package-lock"
      ]
    }

    常用命令

    lerna publish: 发布所有有更新的包

    在默认的固定模式(Fixed mode)下,这个命令会检查 packages 目录下哪些包的文件有更新(lerna.json 中 command.publish.ignoreChanges 除外),然后把 lerna.json 中的 version 与有更新的包中 package.json 的 version 字段更新到一个新的版本号上,最后把这些有更新的包都发布到远程仓库上。

    lerna bootstrap: 启动建立包相互之间的 node_modules 链接

    这个命令会根据各个包下 package.json 里面的 dependencies 和 devDependencies 配置,使用 symlink 在各个包的 node_modules下面建立引用关系。这样就解决了相互之间有依赖而无法联调的问题。

    lerna changed: 查看哪些包有更新,可以发布一个新的版本

    lerna diff [package?]: 查看包都更新了些什么

    lerna run [script]: 使用 npm 运行每个包下面的 [script]

    参考:

    6. 示例

    单个包的 node 项目可以参考我的项目:sclean

    单个包的前端项目可以参考我的项目:see-fetch

    多个包的项目可以参考我的项目:lila

    后续

    更多博客,查看 https://github.com/senntyou/blogs

    作者:深予之 (@senntyou)

    版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证

  • 相关阅读:
    初拾Java(问题一:404错误,页面找不到)
    新年新气象--总结过去,展望未来
    接口测试[整理]
    [转]SVN-版本控制软件
    浅谈黑盒测试和白盒测试
    Bug管理工具的使用介绍(Bugger 2016)
    P2805/BZOJ1565 [NOI2009]植物大战僵尸
    近期学习目标
    P3643/BZOJ4584 [APIO2016]划艇
    P5344 【XR-1】逛森林
  • 原文地址:https://www.cnblogs.com/lishanyang/p/12380048.html
Copyright © 2011-2022 走看看