很多前端開發者學習到必定階段都會去封裝一些本身的組件並將其開源。筆者在學習過程當中發現,發佈的資源包基本分爲兩類:javascript
那麼這兩種方式有何不一樣呢,他們的使用場景如何,具體的操做步驟又是怎麼樣的。本文將基於這兩種發佈方式,對比他們的不一樣,詳解其步驟,並對在封裝Vue組件和發佈npm依賴過程當中所遇到的問題進行概括和解答。相信對於更加全面的瞭解前端工程化和npm發佈流程會有些許幫助。css
本文將涉及到:html
待封裝的Vue組件(組件) 需引用的第三方依賴(第三方依賴) 測試使用的Vue項目(項目)
爲了後文不至混淆,將分別使用括弧中內容指代,請讀者注意區分。前端
這種方式是將封裝好的組件最終打包成一個js文件發佈。這種方式使得發開和調試時更接近與一個前端項目。可是一旦引用圖片等靜態資源需經過BASE64方式打包到js,而對於字體一類較大的靜態資源則根本沒法被引用。vue
適用範圍:沒有或極少的依賴第三方插件、圖片的組件的封裝或JS方法的封裝java
使用webpack構建前端工程,此處注意webpack配置文件應當區分開發和打包。base.js
、dev.js
和build.js
經過merge語句連接。node
// 項目結構 module |——src | |——asset | |——components // 組件包文件夾 | | |——index.js // 組件包打包入口 | | └——componentA.vue // 組件 | |——pages // 供開發時預覽的頁面 | |——router | |——template // html模板 | |——tools | |——app.vue // 供開發時預覽的vue入口 | └——main.js // 供開發時預覽的項目入口 |——webpack // webpack配置文件夾 | |——base.js // 通用配置 | |——dev.js // 開發用配置 | └——build.js // 打包用配置 |——package.json └——README.md
只放基礎配置如module
和通用的plugins
,不要包含打包入口,和出口。webpack
htmlWebpackPlugin
和WebpackDevServer
服務相關。var webpack = require('webpack'); config.entry = { app:[path.join(APP_SRC, 'main.js')], vendors: [ 'vue', 'vuex', 'vue-router', 'axios' ] }, config.entry.app.unshift("webpack-dev-server/client?http://localhost:8088/") config.plugins.push(new htmlWebpackPlugin({ hash: true, minify: { removeComments: true, collapseWhitespace: true, }, // favicon: path.join(APP_SRC, '/asset/images/ico.ico'), template: path.join(APP_SRC, '/template/index.html'), })) var compiler = webpack(config); var serve = new WebpackDevServer(compiler, { quiet: false, stats: { colors: true }, compress: true, //gzip壓縮 publicPath: 'http://localhost:8088/', contentBase: '../dist/', //默認狀況下,webpack-dev-server會從項目的根目錄提供文件,能夠經過此選項設置文件的目錄名 historyApiFallback: true, //當設置爲true時,訪問全部服務器上不存在的文件,都會被重定向到/,也就是index.html文件 }).listen(8088);
components
目錄下的index.js
(index.js
引入並導出咱們須要封裝的組件)。var config = require("./base.js"); module.exports = merge(config, { entry: [path.join(APP_SRC, '/components/index.js')], output: { path: APP_DIST, filename: 'index.js', library: 'module_name', // 指定的就是你使用require時的模塊名 libraryTarget: 'umd', // 指定輸出格式 umdNamedDefine: true // 會對 UMD 的構建過程當中的 AMD 模塊進行命名。不然就使用匿名的 define }, devtool: false, mode: 'production', });
package.json
中須要包含引包的入口,包名稱和版本號。項目在引用組件時會根據main
找到組件入口。ios
{ "name": "my_module", "version": "1.0.0", "main": "dist/index.js" ... }
組件開發無需多說,只要執行npm run dev
將所需封裝的組件引入到預覽頁面中開發調試便可。
組件入口component/index.js需引入並導出組件,更加詳細請看下一章節。web
手動修改package.json
中的version
或者執行npm version patch
生成迭代一個版本
npm run build
注意這一須要登錄官方倉庫,若是以前鏈接的是淘寶鏡像須要線切換回來。下面是查看倉庫源和切換倉庫的命令。
npm config get registry // 查看倉庫源 npm config set registry https://registry.npm.taobao.org npm config set registry http://registry.npmjs.org
登錄npm,輸入帳號、密碼、郵箱
npm login
npm publish
封裝好的組件不通過打包,直接發佈,用戶在引用時不是引用一個獨立的js文件,而是用過一個入口文件引用一些列的文件。這種方式由於不是在單獨引用一個js因此能夠完美解決第三方插件的引用、圖片、字體等靜態文件的引用可是對於組件項目自己而言開發時的預覽調試方法則須要另尋他路。並且筆者暫時沒有想到不適用測方法的,是筆者認爲較爲完美的封裝發佈方案。
由於無需打包,所以再也不須要webpack配置,項目結構也更加精煉。能夠將組件的入口已到根目錄。
// 項目結構 module |——src | |——asset | |——components // 組件包文件夾 | | |——componentA // 組件A | | └——componentB.vue // 組件B | └——tools |——index.js // 組件入口 |——package.json └——README.md
組件的名字、版本、入口文件這三個屬性必備以外,須要注意的是dependencies
中記錄的第三方依賴都會在執行npm install
的時候被安裝。
{ "name": "my_module", "version": "1.2.16", "main": "index.js", "dependencies": { "view-design": "^4.0.2", ... } ... }
使用正確的相對路徑將組件和靜態文件引入到index.js
import './src/asset/css/index.less' import ComponentA from './src/components/ComponentA.vue' import ComponentB from './src/components/ComponentB.vue'
若是你想經過Vue.use(MyComponent)
的方式使用組件,須要導出一個包含了全部組件的對象,並給這個對象定義install
方法供Vue.use()方法調用。
let ModuleObj = { ComponentA, ComponentB } let MyModule = {} MyModule.install = (Vue) => { for (let i in ModuleObj) { Vue.component(i, ModuleObj[i]) } } export default MyModule
export { ComponentA, ComponentB }
以引用iview爲例,在組件(components/ComponentA.vue)內部局部註冊iview組件。這樣至關於按需加載有助於減少最終項目打包的體積。
<script> import { Poptip, Dropdown, DropdownMenu, DropdownItem, Icon, Input } from 'view-design'; export default { components: { Poptip, Dropdown, DropdownMenu, DropdownItem, Icon, Input } } </script>
使用正確的相對路徑引用css、圖片或字體,若是以前習慣使用webpack的alias路徑別名,此時固然也是不生效的。
無需打包,但一樣須要維護版本,直接發佈
手動修改package.json
中的version
或者執行npm version patch
生成迭代一個版本
npm login npm publish
由於組件項目再也不有供開發調試的特面,所以須要在引用組件的項目中對組件進行調試,安裝組件以後,在node_module
中找到組件的所在的文件夾,進入修改便可完成調試。最後將調試好的組件文件夾拷貝出來,除package.json
單獨維護,發佈便可。
兩種引用方式:
// 全局安裝 import MyModule from 'my_module' Vue.use(MyModule) // 按需加載 import { ComponentA, ComponentB } from 'my_module' Vue.component('ComponentA', ComponentA) Vue.component('ComponentB', ComponentB)
打包發佈 | 非打包發佈 | |
---|---|---|
webpack | 須要配置 | 無需配置 |
發佈 | 發佈前須要打包 | 發佈前無需打包 |
引用靜態文件 | 較小的圖片能夠經過BASE64方式打包僅js文件 | 隨意使用 |
引用第三方依賴 | 能夠引用,但若是第三方依賴包含較多的靜態文件時可能會出現引用不到的狀況 | 隨意引用 |
被應用的文件 | 一個打包好的js | 組件的入口文件 |
調試方法 | 在組件項目中便可調試 | 須要在引用組件的項目中的node_module中對用模塊中調試 |
對比兩種方式,筆者更傾向於後者,但只要理解了前端項目引用依賴的原理就會發現其實二者本質上都是同樣的,讀者可根據本身的須要選擇一種方式進行封裝。文中若有錯誤也但願各位不吝賜教及時指出。