Write your own NPM package and publish it to NPM

When it comes to NPM packages, they will give people a particularly lofty feeling, and after writing a package, if someone uses it, they will have a great sense of achievement. The joy of programmers is so simple.

Anyone who came up with the idea of writing an NPM package is probably familiar with modularity and is familiar with either React or Vue.

Webpack5 + React + ESLint +tslint we use webpack scaffolding to write our own NPM package with React. The following content is also based on this.

Scaffolding is also available

1. Differences

The directory structure of the NPM package is different from the normal scaffolding structure

  1. The startup directory is different: we used to write the entry file in SRC, but the NPM package entry file cannot be in SRC because NPM packages our source code and cannot include HTML.

    So extract the index.jsx and index.html files into the example file. The example file should be the same as SRC.

    The structure and contents are as follows

    index.jsx

    import React from 'react'; import { render } from 'react-dom'; import ReactDemo from '.. /src'; const App = () => <ReactDemo />; render(<App />, document.getElementById('root'));Copy the code

    index.html

    <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, Initial scale = 1.0 "/ > < title > Document < / title > < / head > < body > < div id =" root "> < / div > < / body > < / HTML >Copy the code

    Then export it in the SRC /index.jsx file

     import App1 from './App';
     export default App1;
    Copy the code

    Configure the NPM package run file

    Create a new webpack.npm.js file in the config folder

    The configuration files are similar. For details, go to webPack5 + React + ESlint +tslint

    Externals: This will tell NPM not to pack the following items.

    const { resolve } = require('path'); const cssLoaders = [ 'style-loader', { loader: 'css-loader', options: { importLoaders: 1, modules: { auto: (resourcePath) => resourcePath.endsWith('.less'), localIdentName: '[local]_[hash:base64:10]', }, }, }, { loader: 'postcss-loader', options: { postcssOptions: { plugins: [['autoprefixer'], require('postcss-preset-env')()], }, }, }, ]; module.exports = { entry: './src/index.tsx', mode: process.env.NODE_ENV, externals: { antd: 'antd', react: 'React', }, output: { libraryTarget: 'umd', filename: 'index.js', path: resolve(resolve(__dirname, '.. '), 'dist'), clean: true, }, resolve: { alias: { '@': resolve(resolve(__dirname, '.. '), 'src/'), }, extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], mainFiles: ['index'], }, devServer: { hot: True, port: 3002, host: '127.0.0.1', compress: true, open: true, proxy: {'/ API ': {target: 'http://127.0.0.1:3002', pathRewrite: {' ^ / API ':'}, secure: false,,}},}, the module: {rules: [{test: /\.(js|jsx)$/, include: resolve(resolve(__dirname, '..'), ''), exclude: /node_modules/, enforce: 'pre', use: [ { loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-react'], // Cache: The previous cache will be read for the second build cacheDirectory: true,},},}, {test: /\.tsx$/, loader: 'ts-loader', exclude: /node_modules/, }, { test: /\.css$/, use: [...cssLoaders], }, { test: /\.less$/, use: [...cssLoaders, 'less-loader'], }, { test: /\.s[ac]ss$/, use: [...cssLoaders, 'sass-loader'], }, { exclude: /.(html|less|css|sass|js|jsx|ts|tsx)$/, test: /\.(jpg|jpe|png|gif)$/, loader: 'file-loader', options: { name: 'imgs/[name].[ext]', outputPath: 'other', }, }, { test: /\.(ect|ttf|svg|woff)$/, use: { loader: 'file-loader', options: { name: 'icon/[name].[ext]', }, }, }, ], }, };Copy the code

    Let’s focus on what’s in package.json

  • Name: the package name, which is used for subsequent searches in NPM

  • Version: Version number. Each release of the NPM package requires an additional version. Each version cannot be repeated.

  • Description: describe

  • Main: The file exposed in this package, it is important to make sure that the file name is exactly the same as the file you packaged. Mine is called “dist/index.js”.

  • Private: true/false Indicates whether it is private. Generally false otherwise only you can use it

  • Flies: exposed folders, what folders are submitted to NPM in the format [“dist”]

  • Keywords: keyword for NPM search

  • Author: the author

  • license: ISC

  • PeerDependencies: indicates that the current NPM package depends on the following environments.

    Complete configuration

    {" name ":" new_webpack_action2 ", "version" : "1.0.24", "m" : ""," main ":" dist/index. Js ", "private" : false, "flies" : [ "dist" ], "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "export NODE_ENV=development && npx webpack serve --config config/webpack.dev.js", "build": "export NODE_ENV=production && npx webpack --config config/webpack.prod.js", "npm": "export NODE_ENV=production && npx webpack --config config/webpack.npm.js" }, "keywords": [ "react", "javascript", "npm" ], "author": "[email protected]", "license": "ISC", "devDependencies": {" @ ant - design/ICONS ":" 4.7.0 ", "@ Babel/core" : "^ 7.15.0", "@ Babel/preset - env" : "^ 7.15.0", "@ Babel/preset - react" : "^ 7.14.5", "@ types/lodash" : "^ 4.14.178", "@ types/react" : "^ 17.0.19", "@ types/react - dom" : "^ 17.0.11", "@ types/react - the router - dom" : "^ 5.3.3", "@ typescript - eslint/eslint - plugin" : "^ 5.11.0", "@ typescript eslint/parser" : "^ 5.11.0", "autoprefixer" : "^ 10.3.2", "Babel - loader" : "^ 8.2.2 Babel - plugin -", "import" : "^ 1.13.3", "CSS - loader" : "^ 6.2.0", "CSS - minimizer - webpack - plugin" : "^ 3.0.2", "eslint" : "^ 8.8.0 eslint - config -", "reality", "^ 19.0.4", "eslint - plugin - import" : "^ 2.25.4", "eslint - plugin - JSX - a11y" : "^ 6.5.1 eslint", "- the plugin - react" : "^ 7.28.0", "eslint - plugin - react - hooks" : "^ 4.3.0", "eslint - webpack - plugin" : "^ 3.1.1 file -", "loader" : "^ 6.2.0", "HTML - webpack - externals - plugin" : "^ 3.8.0", "HTML - webpack - plugin" : "^ 5.5.0", "less" : "^ 4.4.1," "less - loader" : "^ 10.0.1", "lodash" : "^ 4.17.21", "mini - CSS - extract - the plugin" : "^ 2.2.0", "postcss - loader" : "^ 6.1.1 postcss - preset -", "env" : "^ 7.4.2", "sass" : "^ 1.38.0", "sass - loader" : "^ 12.1.0", "speed - measure - webpack - plugin" : "^ 1.5.0 style -", "loader" : "^ 3.2.1", "stylelint" : "^ 13.13.1", "stylelint - config - standard" : "^ 22.0.0 terser - webpack -", "plugins" : "^ 5.1.4 ensuring", "thread - loader" : "^ 3.0.4", "ts - loader" : "^ 9.2.5", "tslint" : "^ also 6.1.3 typescript", ""," ^ 4.5.5 ", "webpack" : "^ 5.68.0", "webpack - cli" : "^ 4.8.0", "webpack - dev - server" : "^ 4.0.0 webpack -", "merge" : "^ 5.8.0", "workbox - webpack - plugin" : "^ 6.4.2"}, "dependencies" : {" antd ":" 4.18.8 ", "axios" : "^ 0.26.0", "react" : "17.0.2", "the react - dom" : "17.0.2", "the react - the router - dom" : "5.2.0"}, "peerDependencies" : {" @ ant - design/ICONS ":" 4.7.0 ", "antd" : "4.18.8", "bizcharts" : "4.1.15", "rc - footer" : "0.6.6", "react" : "17.0.2", "the react - dom" : "17.0.2", "the react - the router - dom" : "5.2.0"}, "browserslist" : {" development ": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ], "production": [">0.2 ", "not dead", "not op_mini all"]}}Copy the code

    Three, publish,

    If the package is released for the first time, run the following command and enter the NPM account, password, and email address that you have registered

      npm adduser
      
    Copy the code

    If the package is not released for the first time, run the following command to log in, also enter the NPM account, password, and email address

      npm login
      
    Copy the code

    Note: when NPM adduser succeeds, you are already logged in by default, so there is no need for NPM login

    Then go to the project folder first and enter the following command to publish

      npm publish
      
    Copy the code

    When the terminal displays the following message, the package version 1.0.0(in your package.json) has been published successfully. Go to the NPM website to find your bag

    + Your filename @0.1.0Copy the code

    Four, an error

    1, if appear

      npm ERR! code E403
      npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/ghost-watermarkdemo - Forbidden
      npm ERR! 403 In most cases, you or one of your dependencies are requesting
      npm ERR! 403 a package version that is forbidden by your security policy, or
      npm ERR! 403 on a server you do not have access to.
    Copy the code

    There are several reasons for this

    Incorrect account password (please check the account password on the official website of NPM) package name (please check whether there is a project with the same name on the official website of NPM, the name depends on the project name field of package.js) Network cause Mirror source problem The mailbox of the newly registered user is not activated. Login your email to activate (below)Copy the code

2, if appear

Change private to false or remove it from your package.json

Update published packages

Updating a package is the same as publishing a package

   npm publish
   
Copy the code

However, the version number must be changed every time it is updated. For example, 1.0.0 must be changed to 1.0.1 before it is released.

The package versioning rules are the same here, using semver (semantic versioning), which means version number: big change. Medium change. Minor change

## Uninstall your distributed packages from NPM

Enter the directory of your project to execute. NPM unpublish –force

NPM WARN using --force Recommended Protections Disabled. - Package name @0.1.0Copy the code

The uninstallation is successful, then the search can not be found on NPM