本次項目的目的,是基於qiankun這個微前端框架寫一個vue專用的插件來方便在vue的項目裏使用。javascript
起初是想用js寫的。但本着如今開發的是一個第三方類庫,要考慮通用性。若是用js寫,若是使用的項目時typescript的vue項目,就會遇到缺乏類型定義文件的問題。因而採用ts開發。這樣申明文件的生成也變得容易一些。css
https://github.com/Hades-li/qiankun-vuehtml
yarn add qiankun-vue
npm install qiankun-vue --save
vue-cli是vue官方的腳手架工具,傻瓜式構建項目,很是好用。但也許它更適合去開發一整套應用,而不是一個小小的第三方庫。前端
vue-cli提供了一個官方的構建庫方法vue
vue-cli-service build --target lib --name myLib [entry]
這樣構建的結果就和官方展現的同樣,會同時生成多個js的庫文件。而實際在項目引用時,咱們只會用到一個。也就是說,咱們根本不但願生成一堆咱們不想要的東西。java
放棄使用vue-cli官方自帶的方法,剩下的方法就是改寫vue.config.js配置來快速實現構建。如下是截取一些重要的代碼段講解node
if (isProd) { config.entry('index').clear().add('./src/index.ts') config.output .filename('index.js') // 輸出文件名 .libraryTarget('umd') // 打包類型 .library('QiankunVue') // 全局變量名稱 ...... }
在生產環境下,入口文件爲src路徑下的入口文件。
輸出文件設置成index.js,目標類型爲umd格式,全局變量爲QiankunVuejquery
if (!isProd) { config.entry('index').clear().add('./example/main.ts') }
在開發環境下,目的不是把src的源代碼打包輸出,而是要運行example中的列子。因此就將入口文件設置成example下的main.ts文件。webpack
// 排除掉Vue config.externals({ vue: { root: 'Vue', commonjs: 'vue', commonjs2: 'vue', amd: 'vue' } })
因爲咱們開發的是vue的插件,因此須要將vue排除掉。git
此時,執行yarn run build後,dist目錄中就會只生成一個index.js文件,固然,因爲我並無屏蔽掉html模板插件,index.html仍是會被生成。
最終我放棄了以上兩種vue-cli的構建方式,由於我發現,打包出來的index.js文件大小,高達120+KB。這個大小明顯偏大。但我卻找不到緣由。
此次改動,目的是作到徹底不依賴vue-cli,開發,生產環境徹底自定義。
build.js-採用函數式方式執行webpack打包。(暫時放棄)
如下是一些重點代碼片斷
基礎配置,包含了生產和開發環境都須要配置
// 預處理.ts文件 { test: /\.ts$/, use: [ 'babel-loader', { loader: 'ts-loader', options: { appendTsSuffixTo: [/\.vue$/], transpileOnly: true } } ], exclude: /node_modules/ }, // 預處理.vue文件 { test: /\.vue$/, loader: 'vue-loader' },
這兩段代碼主要是預處理.ts文件和.vue文件。
babel-loader是可選的,做用是將es6代碼轉成es5用於兼容瀏覽器。現在的chrome,edge,firefox等現代瀏覽器,對於es6甚至es7支持已經很好了。不加babel-loader,打包文件尺寸能進一步縮小,運行效率還能更高一些,但本着也許還有人用ie的態度,順手加一下吧。
// 預處理scss { test: /\.s[ac]ss$/, use: [ env.NODE_ENV !== 'production' ? 'vue-style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader' ] }, // 預處理css { test: /\.css$/, use: [ env.NODE_ENV !== 'production' ? 'vue-style-loader' : MiniCssExtractPlugin.loader, 'css-loader' ] },
預處理scss,和css樣式。其實在vue-cli構建出來的項目中,還能支持less,stylu另外兩種預編譯樣式文件,但咱們如今是自定義webpack配置,本着,用到什麼就配什麼原則,只須要知足本身的需求便可。
// 預處理圖片 { test: /\.(png|jpe?g|gif|webp)(\?.*)?$/, loader: 'url-loader', options: { limit: 4096, esModule: false, // 5.0版本以上要加 fallback: { loader: 'file-loader', options: { name: 'img/[name].[hash:8].[ext]' } } } }
預處理圖片,這裏要着重說一下這個配置項的坑。此配置用於解析圖片/文件路徑,以及對圖片進行base64轉換。起初,我是直接用vue-cli審查出了一個webpack配置文件,將這部分拷貝過來,和以上代碼相比,僅僅是沒有esModule: false這個參數。運行的結果是,全部圖片不展現,查看圖片路徑是這樣<img src=[object module]>
。因而加上esModule:false就ok了。
以上緣由是因爲vue-loader在對.vue文件解析時,
<img src="../image.png">
標籤會被編譯成
createElement('img', { attrs: { src: require('../image.png') // commonJS語法導入函數 如今這是一個模塊的請求了 } })
require是commonJS規範的導入函數。而url-loader默認是識別es6的導入語法,即import。因而,最終轉換出的代碼就沒法正常顯示圖片。esModule: false就是啓用commonJS引入方式。
那爲何vue-cli構建出來的項目則不須要配置這個參數?
由於vue-cli所採用的url-loader版本號還停留在2.x.x。而最新版本已經到了4.x.x。舊版本url-loader是沒有這個限制機制。新版url-loader是鼓勵採用es6的標準規範來引入文件。commonJs是nodejs的規範。
plugins: [ new VueLoaderPlugin(), // 配合vue-loader new ForkTsCheckerWebpackPlugin(), // 將ts-loader類型檢查跑在一個獨立線程加速編譯 new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"' + env.NODE_ENV + '"', BASE_URL: '"/"' } }), // 給瀏覽器代碼中添加全局變量 new FriendlyErrorsPlugin(), // 友好的錯誤提示 new MiniCssExtractPlugin(), // css提取 new CaseSensitivePathsPlugin() // 嚴格路徑大小寫 ]
以上這些插件基本都是看着vue-cli審查加入的。有的能夠不加,但加了,對於開發都是有極大幫助的。
生產環境下的配置。
module.exports = merge(baseConf({ NODE_ENV: env }), { mode: env, entry: './src/index.ts', output: { path: resolve('dist'), filename: 'index.js', publicPath: '/', chunkFilename: 'js/[name].[contenthash:8].js', libraryTarget: 'umd', library: 'QiankunVue' }, externals: { vue: { root: 'Vue', commonjs: 'vue', commonjs2: 'vue', amd: 'vue' } }, plugins: [ // 清理dist文件夾 new CleanWebpackPlugin() ] })
生產環境配置較爲簡單,首先經過webpack-merge
這個插件將webpack.config.base.js的配置合併過來,添加entry,和output的配置項,而且用cleanwebpackPlugin插件清理一下dist目錄,就能夠一鍵打包了。
開發環境下的配置。
entry: './example/main.ts', output: { path: resolve('dist'), filename: 'app.js', publicPath: '/' }, devServer: { contentBase: resolve('dist'), port: 8080, hot: true, progress: true, // 0-100%的進度提示 quiet: true // 去掉一堆告警信息 }, devtool: 'eval-source-map',
開發環境,一樣合併webpack.config.base.js,改寫一下entry指向example/main.ts。
配置一下開發服務器devServer,切記,別忘了安裝webpack-dev-server
這個包。
plugins: [ new webpack.HotModuleReplacementPlugin(), // 支持熱模塊替換 new HtmlWebpackPlugin({ title: 'qiankun', template: resolve('public/index.html'), favicon: resolve('public/favicon.ico') }), // 配置index.html模板 new CopyWebpackPlugin([ { from: resolve('public'), to: resolve('dist'), toType: 'dir', ignore: ['index.html'] } ]) // 拷貝插件,用於拷貝一些不參與打包的靜態資源至dist目錄 ]
這些都是開發模式下必要的插件
以上的這些webpack配置,比起vue-cli提供的要少不少,好比咱們甚至都沒有針對.js文件編譯loader配置項,由於咱們的項目中純玩ts。實際用vue-cli構建的ts項目是能夠進行js,ts混合開發的。但純手寫webpack的目的,就是隻配本身須要的。
本期重點介紹webpack配置,這也是此項目裏難點之一,耗時費力。
開發一個標準的js庫,無論你是用js開發仍是ts,現在,都是要給本身的庫寫ts的類型申明文件。像相似lodash,jquery這些著名的庫,早期都是沒有申明文件。致使若是用於ts項目開發,類型檢測機制就沒法進行(早期沒有typescript)。但如今,這些庫都已經將類型申明補充進來了。
類型申明能夠手寫,但太費事。最好固然是自動生成。
按照官方說法,在tsconfig.js中配置了declaration: true
的屬性時,就能夠自動生成。但實際是沒有任何反應。固然,你若是直接用tsc --declaration命令行編譯,則能夠生成,目前這是個遺留問題。若是有大神知道解決方法忘指教。