Подробное объяснение создания собственного пакета NPM с нуля.

NPM
CoderMonkey CoderMonkey
Пожалуйста, указывайте автора и источник при перепечатке

Оригинальная ссылкаyuque


Раньше JavaScript мог работать только на стороне браузера.

В среде Nodejs JavaScript также может работать на бэкэнде.

NPM — это менеджер пакетов JavaScript для Nodejs,

Предусмотрено большое количество колес, что позволяет старому программисту-драйверу ускориться и взлететь в одно мгновение.


Помимо работы и учебы,

Фермеры кода, которые не (ню) желают (ли) одиноки (шан) одиноки (цзинь), должны попробовать это, если у них есть возможность.

Стройте колеса, стройте автомобили.


Ниже показан процесс сборки колеса дворовым рабочим,

Запишите разработку простого пакета структуры данных JS,

Поделитесь и обсудите с коллегами.


В этом примере дорожный рабочий создал пакет, использующий JavaScript для реализации структур данных.
npm install data-struct-js
https://github.com/codermonkie/data-struct-js


0. Предпосылки


Предполагается, что Nodejs установлен, а NPM будет установлен вместе с Nodejs.

Если нет среды Node, не должно быть необходимости в разработке пакета NPM.


1. Регистрация пользователя NPM


Поскольку это пакет NPM, естественно сначала иметь учетную запись NPM.

Регистрация очень простая, заходите на официальный сайт.

[официальный сайт НПМ](www.npmjs.com/)


Другой: Если вы учитесь, веб-сайт документации на китайском языке здесь хорош:

[Документация NPM на китайском языке](www.npmjs.cn/)


Запомните имя пользователя и пароль для использования при публикации.


2. Создайте новый репозиторий и инициализируйте проект NPM.


2.1 Создайте новый репозиторий на Github или Gitee

Код проекта дорожных рабочих называетсяdata-struct-js.

Клонировать на локальный.

git clone https://github.com/CoderMonkie/data-struct-js.git


2.2 Инициализация проекта NPM

VSCode открывает папку data-struct-js и выполняет ее в терминале.

npm init -y

Если -y не добавлен, требуется пошаговое подтверждение или ввод вручную

Добавить -y Все параметры будут сгенерированы по умолчанию


Приведенная выше команда автоматически сгенерировала для нас файл package.json.

{
  "name": "data-struct-js",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/CoderMonkie/data-struct-js.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/CoderMonkie/data-struct-js/issues"
  },
  "homepage": "https://github.com/CoderMonkie/data-struct-js#readme"
}


Каждый элемент должен быть соответствующим образом изменен в соответствии с реальной ситуацией.

где URL-адрес,

Он создается на основе информации git нашего проекта github.

git информация существует в.gitпапка.

Мы будем делать конкретные пояснения для каждого атрибута, когда мы его модифицируем.


3. Подготовьтесь к началу разработки пакета NPM


3.1 Отредактируйте файл package.json


Вот описание связанных элементов атрибута,

  • имя: название проекта
  • версия: версия пакета
  • описание: информация описания
  • main: указать файл входа
  • скрипты: скриптовые команды
  • Репозиторий: Адрес репозитория исходного кода
  • ключевые слова: ключевые слова
  • автор: информация об авторе
  • лицензия: тип авторского права
  • ошибки: отзывы об ошибках
  • домашняя страница: домашняя страница проекта


в,

Предметы, которые должны быть включены:nameа такжеversion

Информация об авторе Формат Официальные рекомендации

Your Name <email@example.com> (http://example.com)

Тип авторского права изменен на наименее ограничительный тип MIT в этом проекте.


Модифицированный файл package.json в этом примере:

{
  "name": "data-struct-js",
  "version": "0.0.1",
  "description": "Provide commonly used data-structures for javascript.",
  "main": "index.js",
  "scripts": {
    "compile": "npx babel src --out-dir compiled"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/CoderMonkie/data-struct-js.git"
  },
  "keywords": [
    "data-structure",
    "javascript"
  ],
  "author": "Mao NianYou <maonianyou@gmail.com> (http://github.com/codermonkie)",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/CoderMonkie/data-struct-js/issues"
  },
  "homepage": "https://github.com/CoderMonkie/data-struct-js#readme"
}


Помимо перечисленных выше,

будутdependenciesа такжеdevDependencies,

Представляют пакеты зависимостей проекта и пакеты зависимостей, используемые при разработке проекта, соответственно.

Здесь это не написано, потому что, когда мы хотим добавить зависимости,

пройти черезnpm install --saveилиnpm install --save-devустановить,

Зависимые пакеты и информация о версии будут добавлены к соответствующим свойствам выше.

В основном ручное редактирование не требуется.


3.2 Планирование каталогов и файлов проекта


может быть сложнее, чем это,

Самая основная структура в этом примере состоит из следующего:

data-struct-js
|--examples
|  |--(for sample files)
|--lib
|  |--(for compiled files)
|--src
|  |--(for development files)
|--.babelrc
|--.gitignore
|--.npmignore
|--index.js
|--LICENSE
|--package.json
|--README.md
|

*Примечание. Выше есть подуровни для папок, другие — для файлов.


3.2.1 Введение в структуру каталогов

  • data-struct-js: корневой каталог этого проекта
  • Примеры: хранить пример файлов для этого проекта
  • lib: хранить результаты компиляции (с учетом совместимости браузеров стандартный JavaScript ES6 компилируется в ES5)
  • src: каталог разработки
  • .babelrc: файл конфигурации babel (при использовании webpack его также можно записать в webpack.config)
  • .gitignore: файл конфигурации git, настройте объекты, чтобы игнорировать управление версиями
  • .npmignore: файл конфигурации npm, настройте объект игнорирования при публикации в npm.
  • index.js: файл экспорта, экспортированный унифицированным
  • Лицензия: информационный файл авторских прав, когда новый склад создан, автоматически генерируется в соответствии с выбором
  • package.json: файл управления проектом, автоматически генерируемый при инициализации проекта.
  • README.md: Файл описания проекта, который может быть сгенерирован при создании нового склада и отредактирован в соответствии с содержимым проекта.
  • Кроме того, при использовании веб-пакета также имеется файл конфигурации webpack.config.


(Примечание. В этом проекте веб-пакет настраивается в примере проекта в разделе examples )


3.2.2 Описание специального файла

.babelrc

babel позволяет нам использовать новейший синтаксис JavaScript,

Не беспокоясь о проблемах совместимости браузера,

Потому что это может помочь нам скомпилировать код ES6 в ES5.

Пример:

{
    "presets": [
        "@babel/preset-env"
    ]
}


.gitignore

Настройте файлы или папки здесь, чтобы управление версиями git их игнорировало.

Конфигурация по умолчанию может быть сгенерирована в соответствии с выбором при создании нового склада.

Если вы редактируете его самостоятельно, у вас должно быть как минимум следующее:

examples/dist/
lib/
node_modules/
.npmignore


.npmignore

Конфигурация объекта публикации без npm.

Пример:

examples/
node_modules/
src/
.babelrc
.gitignore
.npmignore


LICENSE

Этот файл создается автоматически в соответствии с типом авторских прав, выбранным при создании нового репозитория.

Пример:

MIT License

Copyright (c) 2019 Mao NianYou

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


package.json

Для файла управления конфигурацией проекта обратитесь к инструкциям, уже сделанным в 3.1 выше.


README.md

Проектная документация с использованием разметки markdown,

Представьте свой проект. Например:

# 背景介绍
# 项目介绍
# 查看示例
# 使用说明
# License
# 联系
# 贡献者/鸣谢

Заполните конкретное содержание в соответствии с вышеуказанными основными элементами.


4. Разработать собственный пакет NPM


После настройки вышеуказанного контента перейдите по основной ссылке,

Разработайте наш пакет NPM.


4.1 Установите связанные зависимости


В этой разработке мы в настоящее время используем только пакеты, связанные с babel.

Выполните следующие команды в терминале VSCode (или другом инструменте командной строки):

npm install --save-dev @babel/cli
npm install --save-dev @babel/core
npm install --save-dev @babel/preset-env


Его также можно сократить до одной из следующих команд:

npm i -D @babel/cli @babel/core @babel/preset-env


--save-dev эквивалентен -D

добавит зависимости к devDependencies


--save эквивалентно -S

добавит зависимости к зависимостям


потому что код используетатрибут классаПримечание, если установлено только вышеперечисленное, запуск babel сообщит об ошибке,

Согласно сообщению об ошибке, также необходимо установить @babel/plugin-proposal-class-properties

Примечание. См. приведенный ниже код ArrayBasedStruct.js.

Error: Cannot find module '@babel/plugin-proposal-class-properties' from...


  1. Установить
npm i -D @babel/plugin-proposal-class-properties


  1. Измените файл конфигурации babel (.babelrc) и добавьте плагины.
{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins": [
      ["@babel/plugin-proposal-class-properties",
          {
              "loose": true
          }
      ]
    ]
}


После завершения установки в файл package.json добавляется поле devDependencies.

{
  "name": "data-struct-js",
  "version": "0.0.1",
  "description": "Provide commonly used data-structures for javascript.",
  "main": "index.js",
  "scripts": {
    "compile": "npx babel src --out-dir compiled"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/CoderMonkie/data-struct-js.git"
  },
  "keywords": [
    "data-structure",
    "javascript"
  ],
  "author": "CoderMonkey <maonianyou@gmail.com> (http://github.com/codermonkie)",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/CoderMonkie/data-struct-js/issues"
  },
  "homepage": "https://github.com/CoderMonkie/data-struct-js#readme",
  "devDependencies": {
    "@babel/cli": "^7.7.5",
    "@babel/core": "^7.7.5",
    "@babel/plugin-proposal-class-properties": "^7.7.4",
    "@babel/preset-env": "^7.7.6"
  }
}


4.2 Реализация кода ES6 (пример: Stack.js)


Потому что предмет этой статьи о том, как опубликовать свой собственный пакет NPM с нуля,

Часть кода является лишь примером, полный код можно посмотреть:

[Github](GitHub.com/cod и обезьяний IE…)


Ниже приведен код реализации структуры стека в этом проекте.

Другие документы, цитируемые в нем,

Прикреплен ниже для справки.

data-struct-js/src/Stack.js

import {
    deepCopy,
    isFunction
} from './common_utils'
import ArrayBasedStruct from './ArrayBasedStruct'

/**
 *栈结构
 *
 * @export
 * @class Stack
 * @extends {ArrayBasedStruct}
 */
export class Stack extends ArrayBasedStruct {
    constructor() {
        super()
    }

    /**
     *将新元素入栈
     *
     * @param {*} element
     * @memberof Stack
     */
    push(element) {
        return this.__items.push(element)
    }

    /**
     *栈顶元素出栈
     *
     * @returns 栈顶元素
     * @memberof Stack
     */
    pop() {
        return this.__items.pop()
    }

    /**
     *查看栈顶元素
     *
     * @returns 栈顶元素
     * @memberof Stack
     */
    peek() {
        if (!this.__items.length) return undefined
        return deepCopy(this.__items[this.__items.length - 1])
    }

    /**
     *遍历栈结构
     *
     * @param {function} callback
     * @param {boolean} [reversal=false]
     * @memberof Stack
     */
    traverse(callback, reversal = false) {
        // 检查回调函数
        if (!isFunction(callback)) return

        var items = this.getItems(this.__items)
        var from = reversal ? items.length - 1 : 0
        var to = reversal ? 0 : items.length - 1
        // 循环条件
        var loopCondition = function (current) {
            if (reversal) {
                return current >= to
            } else {
                return current <= to
            }
        }
        // 游标前进
        var stepIn = function (current) {
            if (reversal) {
                return current - 1
            } else {
                return current + 1
            }
        }

        // 进行遍历
        for (var index = from; loopCondition(index); index = stepIn(index)) {
            var element = items[index];
            callback(element, index)
        }
    }

    /**
     *转为字符串
     *
     * @returns
     * @memberof Stack
     */
    toString() {
        return this.__items.map(element => element.toString()).join(' ')
    }
}


data-struct-js/src/common_utils.js
Распространенные способы сделать это самостоятельно

/**
 *深拷贝
 *
 * @export
 * @param {*} source 要拷贝的对象
 * @returns 深拷贝结果
 */
export function deepCopy(source) {
    var dest
    if(Array.isArray(source)) {
        dest = []
        for (let i = 0; i < source.length; i++) {
            dest[i] =deepCopy(source[i])
        }
    }
    else if(toString.call(source) === '[object Object]') {
        dest = {}
        for(var p in source){
            if(source.hasOwnProperty(p)){
                dest[p]=deepCopy(source[p])
            }
        }
    }
    else {
        dest = source
    }
    return dest
}

/**
 *判断传入参数是否为函数
 *
 * @export
 * @param {*} func 参数(函数)
 * @returns true:是函数 false:不是函数
 */
export function isFunction (func) {
    if (!func || toString.call(func) !== '[object Function]') return false
    return true
}


data-struct-js/src/ArrayBasedStruct.js

Базовый класс, поставляемый в структуру стека

import { deepCopy } from "./common_utils"

/**
 *基于数组实现的数据结构的基类
 *
 * @class ArrayBasedStruct
 */
export class ArrayBasedStruct {
    constructor() {
        this.__items = []
    }

    /**
     *获取所有元素
     *
     * @returns 元素集合
     * @memberof Stack
     */
    getItems () {
        return deepCopy(this.__items)
    }

    /**
     *数据结构实例中是否包含元素
     *
     * @readonly
     * @memberof ArrayBasedStruct
     */
    get isEmpty() {
        return this.__items.length === 0
    }

    /**
     *数据结构实例的元素个数
     *
     * @readonly
     * @memberof ArrayBasedStruct
     */
    get size() {
        return this.__items.length
    }

    /**
     *清空数据结构中的元素
     *
     * @memberof ArrayBasedStruct
     */
    clear() {
        this.__items.length = 0
    }
}


Унифицированный экспорт через файл index.js

data-struct-js/index.js

import { Stack } from './lib/Stack'
export { Stack }

Примечание. В настоящее время в этом примере присутствует только Stack, сюда также экспортируются последующие дополнения.


4.3 Компиляция с помощью Babel


Помните команду скрипта, которую мы настроили в package.json,

  "scripts": {
    "compile": "npx babel src/ --out-dir lib"
  },


Метод выполнения:

npm run compile


Результаты:

> data-struct-js@0.0.1 compile F:\path\to\data-struct-js
> npx babel src/ --out-dir lib

Successfully compiled 3 files with Babel.


Скомпилируйте и выполните успешно, вы можете видетьdata-struct-js/lib/Скомпилированные файлы генерируются в папке.

Когда созданный нами пакет используется другими, именно эти скомпилированные файлы загружаются и импортируются.


5. Протестируйте свой собственный пакет NPM


Как и обычная разработка проекта, разработка пакета NPM также требует тестирования.

С помощью тестирования уменьшите или избегайте ошибок.


5.1 Создать демонстрационный проект

data-struct-js/examples/Под путь, наш новый тестовый проект.

cd examples
npm init
package name: data_struct_js_demo

Сгенерированный файл проекта package.json:

{
  "name": "data_struct_js_demo",
  "version": "1.0.0",
  "description": "demo for data-struct-js",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT"
}


npm install --save-dev ../../data-struct-js

data-struct-js/examples/src/index.js

// 直接引入原文件
import Stack from '../../src/Stack'

// 或编译后的也可以
// import Stack from '../../lib/Stack'



=> data-struct-js/index.js


npm i -D webpack webpack-cli webpack-dev-server
npm i -D html-webpack-plugin clean-webpack-plugin


data-struct-js/examples/package.json

{
  "name": "data_struct_js_demo",
  "version": "1.0.0",
  "description": "Demo for data-struct-js",
  "main": "index.js",
  "scripts": {
  },
  "author": "CoderMonkey <maonianyou@foxmail.com>",
  "license": "MIT",
  "devDependencies": {
    "babel-loader": "^8.0.6",
    "clean-webpack-plugin": "^3.0.0",
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.41.3",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.9.0"
  }
}


data-struct-js/examples/webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const htmlWebpackPlugin = new HtmlWebpackPlugin({
    template: path.join(__dirname, "./src/index.html"),
    filename: "./index.html"
});
const {CleanWebpackPlugin} = require("clean-webpack-plugin");

module.exports = {
    mode: 'development',
    entry: path.join(__dirname, "./src/index.js"),
    output: {
        path: path.join(__dirname, "dist/"),
        filename: "[name].[hash:6].js"
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                use: "babel-loader",
                exclude: /node_modules/
            }
        ]
    },
    plugins: [
        htmlWebpackPlugin, new CleanWebpackPlugin()
    ],
    resolve: {
        extensions: [".js", ".jsx"]
    },
    devServer: {
        port: 8080
    }
};


data-struct-js/examples/package.json

// ...略...
  "scripts": {
    "start": "webpack-dev-server --open",
    "build": "webpack --config webpack.config.js"
  },
// ...略...


data-struct-js/examples/src/index.js

// 直接引入原文件
import { Stack } from '../../src/Stack'

var stack = new Stack()
for (var i = 0; i < 5; i++) {
    stack.push(i)
}
console.log('isEmpty: ', stack.isEmpty)
console.log('size: ', stack.size)
console.log(stack.toString())
console.log(`pop: `, stack.pop())

stack.traverse((ele,index)=>{
    console.log(`Traversing-Stack:${index}: ${ele}`)
})

stack.traverse((ele,index)=>{
    console.log(`Traversing-Stack:${index}: ${ele}`)
}, true)

console.log(`claer: `, stack.clear())
console.log('isEmpty: ', stack.isEmpty)
console.log('size: ', stack.size)

data-struct-js/examples/src/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Demo of data-struct-js</title>
</head>
<body>
</body>
</html>


npm run start


// 直接引入原文件
import { Stack } from '../../src/Stack'

var stack = new Stack()
for (var i = 0; i < 5; i++) {
    stack.push(i)
}
console.log('isEmpty: ', stack.isEmpty)
// isEmpty:  false

console.log('size: ', stack.size)
// size:  5

console.log(stack.toString())
// 0 1 2 3 4

console.log(`pop: `, stack.pop())
// pop:  4

stack.traverse((ele,index)=>{
    console.log(`Traversing-Stack:${index}: ${ele}`)
})
// Traversing-Stack:0: 0
// Traversing-Stack:1: 1
// Traversing-Stack:2: 2
// Traversing-Stack:3: 3

stack.traverse((ele,index)=>{
    console.log(`Traversing-Stack:${index}: ${ele}`)
}, true)
// Traversing-Stack:3: 3
// Traversing-Stack:2: 2
// Traversing-Stack:1: 1
// Traversing-Stack:0: 0

console.log(`claer: `, stack.clear())
// claer:  undefined

console.log('isEmpty: ', stack.isEmpty)
// isEmpty:  true

console.log('size: ', stack.size)
// size:  0


TODO




npm ERR! publish Failed PUT 403
npm ERR! code E403
npm ERR! [no_perms] Private mode enable, only admin can publish
this module [no_perms] Private mode enable,
only admin can publish this module: data-struct-js


npm login


npm ERR! code E409
npm ERR! Registry returned 409 for PUT on
https://registry.npm.taobao.org/-/user/org.couchdb.
user:maonianyou: [conflict] User maonianyou already exists


> nrm use npm

    Registry has been set to: https://registry.npmjs.org/


> npm login
Username: yourname
Password: (yourpassword)
Email: (this IS public) yourname@somemail.com
Logged in as yourname on https://registry.npmjs.org/.


npm ERR! publish Failed PUT 403
npm ERR! code E403
npm ERR! you must verify your email before publishing a new package:
https://www.npmjs.com/email-edit : your-package


npm ERR! publish Failed PUT 403
npm ERR! code E403
npm ERR! You do not have permission to publish "xxxxxxx". Are you logged in as
the correct user? : xxxxxxxxx



npm run compile
npm publish


data-struct-js/package.json

// ...略...
  "scripts": {
    "dopublish": "npm run compile && npm publish"
  },
// ...略...

npm run dopublish


>npm publish
npm notice
npm notice package: data-struct-js@0.0.1
npm notice === Tarball Contents ===
npm notice 866B  package.json
npm notice 55B   index.js
npm notice 1.1kB LICENSE
npm notice 26B   README.md
npm notice 1.8kB lib/ArrayBasedStruct.js
npm notice 947B  lib/common_utils.js
npm notice 5.1kB lib/Stack.js
npm notice === Tarball Details ===
npm notice name:          data-struct-js
npm notice version:       0.0.1
npm notice package size:  3.7 kB
npm notice unpacked size: 9.9 kB
npm notice shasum:        2001495314blsd9gaj9g0b7b15aewr6we5207aac
npm notice integrity:     sha512-UzOx7tFP8/qJp[...]DPJ1wherlFJyQ==
npm notice total files:   7
npm notice
+ data-struct-js@0.0.1




npm install data-struct-js


import { Stack } from 'data-struct-js'


npm unpublish --force your-package-name

npm unpublish <package-name>@<version>



npm Support




npm ERR! publish Failed PUT 403
npm ERR! code E403
npm ERR! You cannot publish over the previously published versions:
0.0.1. : data-struct-js





Code status Stage Rule Example version

1

First release
New product
Start with 1.0.0 1.0.0

2

Backward compatible bug fixes

Patch release
Increment the third digit
1.0.1

3

Backward compatible new features

Minor release

Increment the middle digit and reset last digit to zero
1.1.0

4

Changes that break backward compatibility
Major release
Increment the first digit and reset middle and last digits to zero
2.0.0



data-struct-js/pakcage.json

{
  "version": "1.0.1"
}


npm publishs


npm version <update_type>

  • patch 0.0.*
  • major *.0.0
  • minor 1.*.0
npm version patch

npm publish




> npm set init.author.email "example-user@example.com"
> npm set init.author.name "example_user"
> npm set init.license "MIT"


@babel/cli
@babel/core
@babel/preset-env


npm install @babel/cli

npm install data-struct-js


@scopename

@codermonkey/data-struct-js


npm publish --access public

@yourscope/packagename

1.0.0 · Public · Published ... ago




npm login --registry=http://reg.example.com --scope=@myco


npm config set @myco:registry http://reg.example.com


docs.npmjs.com/misc/scope



CoderPower_QRCode.jpg

-end-