[toc]javascript
這篇文章主要記錄了從零發佈一個vue的npm包(包含一個簡單的指令和一個vue組件)的實踐過程及些許心得。
這裏咱們經過@vue/cli拉取簡單配置的模板來初始化一個2.X的項目,不瞭解的同窗能夠看下vueCli3官方文檔html
vue init webpack-simple vue-directive-kit
初始化的項目目錄以下vue
├── README.md ├── index.html ├── package.json ├── src │ ├── App.vue │ ├── assets │ └── main.js └── webpack.config.js
接下來作一些改動。src
目錄改成examples
用於本地開發及案例展現,新增一個packages
目錄用於存放組件源碼及導出文件。java
├── README.md ├── examples │ ├── App.vue │ └── main.js ├── index.html ├── package.json ├── packages │ ├── componentName // 單個組件 │ │ ├── index.js │ │ └── src │ │ └── componentName.vue │ └── index.js // 導出文件 └── webpack.config.js
因爲文件名稱作了改動,webpack的打包配置也要作對應修改。默認webpack.config.js
會導出一個對象,這裏咱們改成導出一個函數,而後由函數把配置對象導出,這樣能夠接受一個經過package.json
傳過來的參數env
,同時修改entry
及output
:webpack
module.exports = env => { return { entry: env.lib ? "./packages/index.js" : "./examples/main.js", output: { // 打包文件的生成路徑 path: path.resolve(__dirname, env.lib ? "./lib" : "./dist"), publicPath: env.lib ? "/lib/" : "/dist/", // 打包後生成的文件名 filename: env.lib ? "vue-directive-kit.js" : "build.js", /** * library指定的就是你使用require時引入的模塊名 * 這裏即是require(「vue-directive-kit」) */ library: env.lib ? "vue-directive-kit" : "", /** * libraryTarget能夠指定打包文件中代碼的模塊化方式,默認爲var,常見有以下幾種: * commonjs/commonjs2: 將你的library暴露爲CommonJS模塊 * amd: 將你的library暴露爲amd模塊 * umd: 將你的library暴露爲全部的模塊定義下均可運行的方式 * 其中AMD和UMD須要指定library,若是不聲明組件庫則不能正常運行, * 這是爲了在瀏覽器上經過script標籤加載時,用AMD模塊方式輸出的組件庫能夠有明確的模塊名 */ libraryTarget: env.lib ? "umd" : "var", /** * 當使用了 libraryTarget: "umd", * 設置umNamedDefine爲true時, * 會對 UMD 的構建過程當中的 AMD 模塊進行命名。不然就使用匿名的 define。 */ umdNamedDefine: env.lib ? true : false, }, }; };
上面的配置能夠知道,咱們須要經過env來控制打包類型。env
須要在package.json
中傳入git
"scripts": { // 本地開發運行npm run dev "dev": "cross-env NODE_ENV=development webpack-dev-server --env --open --hot", "build": "cross-env NODE_ENV=production webpack --env --progress --hide-modules", // 須要發佈的時候執行npm run lib打包 "lib": "cross-env NODE_ENV=production webpack --env.lib --progress --hide-modules" },
在packages/componentName/src/componentName.vue
文件中寫以下你內容。固然這個是爲了演示內容很簡單,其實這個文件就是真實的組件了。github
<template> <div> <h1>我是一個組件</h1> </div> </template> <script> export default { name: 'componentName', data () { return { } } } </script>
在packages/componentName/src/index.js
中註冊並導出單個組件web
// 引入組件 import componentName from './componentName/src' componentName.install = Vue => Vue.component(componentName.name, componentName); if (typeof window !== 'undefined' && window.Vue) { window.Vue.use(componentName); } export default componentName;
咱們增長一個名稱爲testDirective
的指令。
建立'packages/testDirective/src/testDirective.js'文件:npm
export default { bind: () => { console.log(`directive bind`); }, inserted: (el, binding) => { console.log(`el:`, el); }, }
建立packages/testDirective/index.js
文件:json
// 引入組件 import testDirective from './src/testDirective' const install = Vue => { Vue.directive('testDirective', testDirective); }; if (typeof window !== 'undefined' && window.Vue) { window.Vue.use({install}); } export default { install };
編輯出口文件packages/index.js
,將packages
目錄下全部的指令及組件統一註冊導出:
// 導入顏色選擇器組件 import componentName from './componentName/src/componentName.vue' import testDirective from './testDirective/src/testDirective' // 存儲組件列表 const components = [ componentName, ] // 存儲指令映射 export const directives = { testDirective, } // 定義 install 方法,接收 Vue 做爲參數。若是使用 use 註冊插件,則全部的組件都將被註冊 const install = function (Vue) { // 遍歷註冊全局組件 components.map(component => Vue.component(component.name, component)) // 遍歷註冊指令 Reflect.ownKeys(directives).map(name => Vue.directive(name, directives[name])) } // 判斷是不是直接引入文件 if (typeof window !== 'undefined' && window.Vue) { install(window.Vue) } export default { // 導出的對象必須具備 install,才能被 Vue.use() 方法安裝 install, // 如下是具體的組件列表 componentName, ...directives, }
到這裏,咱們的包裏就包含了一個名爲componentName
的組件和一個名爲testDirective
的指令,本地測試一下,先在examples/main.js
中引入
// 單獨引入指令文件 // import pkgName from '../packages/test-directive/index' // 總體引入包 import pkgName from '../packages/index' Vue.use(pkgName)
在examples/App.vue
中使用
<template> <div id="app"> <h1 v-test-directive>Test Directive</h1> <component-name></component-name> </div> </template>
而後運行yarn dev
本地查看效果
看起來本地測試已經沒有問題,能夠打包發佈了。
不過在打包發佈以前,須要先作一些準備工做。
一個標準的npm包或者開源項目都會一個有完善且好看的README幫用戶快速瞭解你的項目。經過generator-standard-readme
能夠快速生成一個README模板
npm install --global yo generator-standard-readme yo standard-readme
package.json
文件爲package.json
增長一些發佈npm包所須要的基本字段:
/** * npm包名,要符合幾個規則: * 1. name的長度必須小於等於214個字符。 * 2. name不能以"."(點)或者"_"(下劃線)開頭。 * 3. name中不能包含大寫字母。 * 4. name最終將被用做URL的一部分、命令行的參數和文件夾名。所以,name不能含有非URL安全的字符。 */ "name": "vue-directive-kit", "description": "A collection of vue directives.", "version": "1.0.1", "author": "slevin <575720013@qq.com>", "license": "MIT", // 是否私有,默認爲true,改成false "private": false, // 是一個字符串的數組。它能夠幫助人們在使用npm search時找到這個包 "keywords": [ "vue", "vue-directive-kit", "vue-directive" ], /** * files字段是一個被項目包含的文件名數組 * 若是你在裏面放一個文件夾名,那麼這個文件夾中的全部文件都會被包含進項目中(除非是那些在其餘規則中被忽略的文件)。 * 你還能夠在包的根目錄或子目錄下提供一個".npmignore"文件來忽略項目包含文件,即便這些文件被包含在files字段中 * 某些文件老是被包含的,不管是否在規則中指定了它們: * package.json * README (and its variants) * CHANGELOG (and its variants) * LICENSE / LICENCE */ "files": [ "lib/vue-directive-kit.js", "package.json", "README.md" ], /** * main字段用來指定入口文件 * */ "main": "lib/vue-directive-kit.js", /** * 指明你的代碼被託管在何處,也就是遠程倉庫的地址 */ "repository": { "type": "git", "url": "git@github.com:slevin57/vue-directive-kit.git" }
隨便找一個項目,安裝這個包進行測試。這裏咱們就在根目錄下再初始化一個vue基本項目用來測試包的使用,而後把npm包文件放到測試項目根路徑執行安裝,同時安裝項目依賴。
vue init webpack-simple test mv xxx.tgz ./test cd test npm i xxx.tgz && npm i
在main.js
中像正常引入第三方包那樣操做就能夠。測試完成後記得刪掉test目錄。
準備操做及測試都作完後就能夠打包發佈了。
先打包
npm run lib
登陸npm,輸入npm註冊的用戶名、密碼及郵箱
npm login
發佈
npm publish
不出意外的話,登陸npm就能夠看到你發佈的包了。發佈的包在72小時內是能夠刪除的,過了72小時就永遠沒法刪除了,因此記得不要隨意發一些沒有意義的包。
若是須要卸載,在發佈後72小時內執行:
npm unpublish <pkg>[@<version>]