先說一下這篇文章的誕生緣由。咱們有一個這樣的項目,相似或者說就是一個儀表板-Dashboard,其中的各個部分可能不是一個部門寫的……咱們須要提供拖拽佈局(大小和位置)和展現的能力。要實現這樣一個功能,想了好幾種方式實現(後面的筆記詳說),最後選擇了這篇筆記的實現方式:寫整個項目的,算是使用方;寫每一個組件的,算是vue類庫(UI、組件庫)的提供方。以後就是咱們如何使用這些類庫的問題了,就像咱們使用element-ui同樣,這樣說就明白了吧!這裏不說父子之間如何通訊以及如何使用類庫,只說如何打包類庫。css
以前老是使用別人的類庫了,沒有本身寫過,今天就着這個機會研究了有了一下,demo算是跑通了,深刻的就須要以後慢慢學習了。html
開始仍是看了一下element-ui是如何將全部的組件打包到一個JS文件,而且能夠CDN方式使用的,發現和咱們寫一個單獨的.vue單文件組件沒有什麼區別,主要是webpack的output和入口文件的寫法有些不一樣,其餘的都大同小異,先看一下outputvue
var path = require('path'); var VueLoaderPlugin = require('vue-loader/lib/plugin'); module.exports = { mode: 'development', // production|development // https://segmentfault.com/a/1190000013712229 entry: "./index.js", output: { path: path.resolve(__dirname, './dist'), publicPath: '/dist/', filename: 'ddztestlib01.js', library: 'ddztestlib01', libraryTarget: 'umd', libraryExport: 'default', umdNamedDefine: true, // globalObject: `(typeof self !== 'undefined' ? self : this)`, // https://stackoverflow.com/questions/49111086/webpack-4-universal-library-target globalObject: 'typeof self !== \'undefined\' ? self : this' // element-ui 寫法 }, module: { rules: [{ test: /\.vue$/, loader: 'vue-loader' }, { test: /\.css$/, loader: 'css-loader' }, { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' }] }, devtool: "source-map", resolve: { alias: { 'vue': 'vue/dist/vue.js' } }, plugins: [ new VueLoaderPlugin() ] }
這裏主要說一下,libraryTarget、libraryExport、umdNamedDefine和globalObject
webpack
一、libraryTarget:打包類庫的發佈格式,這裏使用UMD,其餘選項不解釋(實際上是……)git
二、libraryExport:這個選項一樣不知道幹什麼的,可是我遇到了一個問題就是開始沒有添加這個選項(雖然看了element-ui的打包,可是我給過濾了),致使使用的時候發現有雙層的「default」,由於不是很瞭解,因此查了一些資料先看看,卻發現和這篇文章說的同樣:webpack組織模塊打包Library的原理及實現,後來發現該文中使用的選項過時了,以後仍是又看了一遍element-ui 才搞定,這一大圈github
三、umdNamedDefine:這個仍是同上,可是添加和不添加這個選項比較一下生成文件你就知道了web
四、globalObject:這個是真不知道了,可是在stackoverflow中無心發現說這是個Bug,地址:https://stackoverflow.com/questions/49111086/webpack-4-universal-library-targetelement-ui
如今看來webpack配置文件處理output某些屬性和咱們正常開發沒有什麼區別,下面看一下他的入口文件:segmentfault
// 一、這裏導入須要導出的組件,統一處理 import DDZComponent01 from './src/components/DDZComponent01.vue'; import DDZComponent02 from './src/components/DDZComponent02.vue'; // 1.一、書寫Vue插件(保證只引入某一個組件時可用),https://cn.vuejs.org/v2/guide/plugins.html DDZComponent01.install = function (Vue) { Vue.component(DDZComponent01.name, DDZComponent01); }; DDZComponent02.install = function (Vue) { Vue.component(DDZComponent02.name, DDZComponent02); }; // 二、遍歷註冊全部的組件(依賴),全局時使用 const components = [ DDZComponent01, DDZComponent02 ]; const install = function (Vue, opts = {}) { components.forEach(component => { Vue.component(component.name, component); }); // 這裏除了註冊組件,還能夠作一些其餘的東西 // 你能夠在Vue的原型上擴展一些方法 // eg:element-ui // Vue.prototype.$message = Message; // 使用:this.$message({message:"xxxxx",type:"success"}); }; // 能夠根據實際狀況,是否須要這段代碼(CDN引入,即可使用全部組件) if (typeof window !== 'undefined' && window.Vue) { install(window.Vue); } // 三、導出類庫的版本、組件、Vue插件須要暴露的install方法 export default { version: '0.0.1', install, DDZComponent01, DDZComponent02 }; // 四、使用方式 // 4.一、使用部分組件 // 4.1.一、 // import { DDZComponent01 } from '……/ddztestlib01.js'; // 局部註冊:components: { ddzcomponent01: DDZComponent01 }, // 全局註冊:Vue.use(DDZComponent01); //這種寫法須要對應的組件暴露install方法 // 4.1.二、 // import * as ddztestlib01 from '……/ddztestlib01.js'; // 這裏的書寫方式應該和導出的寫法有關係 // 局部註冊:components: { ddzcomponent01: ddztestlib01.DDZComponent01 }, // 全局註冊:Vue.use(ddztestlib01.DDZComponent01); //這種寫法須要對應的組件暴露install方法 // 4.二、使用類庫中的全部組件 // 4.2.一、 // import * as ddztestlib01 from '……/ddztestlib01.js'; // 這裏的書寫方式應該和導出的寫法有關係 // Vue.use(ddztestlib01); //這裏的使用就是調用對象的install方法 // 4.2.二、cdn方式使用 // <script src="……/ddztestlib01.js"></script> //若是window.Vue存在,則自動註冊所有組件 // 4.三、使用systemjs異步加載(測試版本:SystemJS 3.1.6) // 加載以後,返回的是該類庫的默認導出對象:{default:{version:,install:,……}}。這種加載方式和CDN相似,若是window.Vue存在,則自動註冊所有組件。因此若是window.Vue存在,返回的對象意義不大;除非window.Vue不存在。注意:組件註冊成功以後在顯示 // 代碼示例: // System.import("……/ddztestlib01.js").then((result) => { // // 成功加載以後,顯示組件 // // 若是window.Vue存在,而且存在相似上面的install方法,則這裏的返回結果沒有什麼意思 // // 至於如何使用,則能夠根據具體狀況而定,選擇本身合適的 // }); // 4.四、使用requirejs異步加載(測試版本:requirejs 2.3.6) // 和systemjs相似,只是使用方式不一樣 // 代碼示例: // requirejs.config({ // paths: { // "ddztestlib01": tempUrl // } // }); // requirejs(["ddztestlib01"], (result) => { // // 成功加載以後,顯示組件 // }); // 4.五、……使用模塊加載器加載JS和CDN方式差很少,只是不一樣的加載器返回的結果不一樣(有支持UMD,有的不支持)
入口文件就不解釋了,在裏面我以爲解釋的夠清楚了,還有類庫中包含的組件這裏就不說了,也沒有什麼好說的就是「Hello World」。less
最後在附上使用類庫的代碼:
<!DOCTYPE html> <html lang="zh-cmn-Hans"> <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>測試個人Vue組件庫:ddztestlib01</title> <style> *, *::before, *::after { box-sizing: border-box; } html, body { height: 100%; width: 100%; margin: 0; } [v-cloak] { display: none; } </style> </head> <body> <div id="myApp" v-cloak> <h3>{{msg}}</h3> <div>下面是組件1的內容</div> <ddzcomponent01 :prop1="ddzcomponent01prop1"></ddzcomponent01> <div>下面是組件2的內容</div> <ddzcomponent02 :prop1="ddzcomponent02prop1"></ddzcomponent02> </div> <script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script> <script src="https://xiaodu114.github.io/vue/vue2.x/PackFirstVueLibrary/dist/ddztestlib01.js"></script> <script> var myApp = new Vue({ el: "#myApp", data() { return { msg: "測試個人Vue組件庫:ddztestlib01", ddzcomponent01prop1: "我在這裏爲組件1的屬性1賦值:" + new Date(), ddzcomponent02prop1: "我在這裏爲組件2的屬性1賦值:" + Math.random(), } } }); </script> </body> </html>
這篇文章就到這裏吧!有寫的不對的地方,敬請指正,很是感謝!