Vue CLI3搭建組件庫並實現按需引入實戰操做

Vue CLI3搭建組件庫並用npm發佈實戰操做中介紹了單個組件的組件庫怎麼開發,本文將一步一步教你們怎麼開發多個組件集成的組件庫,怎麼實現組件庫按需引入。以爲有用點個贊支持一下。css

本文將略過安裝Vue CLI三、搭建組件庫的項目、清潔組件庫項目的步驟,不懂的地方能夠看Vue CLI3搭建組件庫並用npm發佈實戰操做html

1、創建兩個git倉庫放本文的示例代碼

2、組件庫項目中webpack一些基礎配置

在Vue CLI3中,項目的webpack配置是要在根目錄下新建vue.config.js來配置。vue

一、區分開發環境和生成環境的配置

由於多入口組件庫中開發環境和生成環境的配置是不一樣,全部要區分開來。 經過process.env.NODE_ENV變量來判斷,生產環境時process.env.NODE_ENVdevelopmentnode

//開發環境配置
const devConfig = {
    //...
}
const buildConfig = {
    //...
}
module.exports = process.env.NODE_ENV === 'development' ? devConfig : buildConfig;
複製代碼

二、更改src文件夾的名字

在Vue組件庫項目中原來src文件夾的內容是demo展現的內容,因此文件名改爲examples,比較形象。webpack

三、從新配置項目入口文件

在vue.config.js文件中配置內容以下:git

const devConfig={
    pages: {
        index: {
            entry: 'examples/main.js',
            template: 'public/index.html',
            filename: 'index.html',
        },
    },
}
複製代碼

四、配置文件別名

文件別名會在寫demo中用到。在vue.config.js文件中配置內容以下:github

const path = require('path');
function resolve(dir) {
    return path.resolve(__dirname, dir)
}
const devConfig = {
    configureWebpack: {
        resolve: {
            extensions: ['.js', '.vue', '.json'],
            alias: {
                '@': resolve('packages'),
                'assets': resolve('examples/assets'),
                'views': resolve('examples/views'),
            }
        }, 
    },
}
複製代碼

五、配置devServer項

在vue.config.js文件中配置內容以下:web

const devConfig  = {
    devServer:{
        port: 8091,//固定端口
        hot: true,//開啓熱更新
        open: 'Google Chrome'//固定打開瀏覽器
    }
}
複製代碼

六、在根目錄下新建packages文件夾

組件的代碼在packages文件夾中開發npm

七、將新增的packages文件夾加入babel轉碼編譯

在vue.config.js文件中配置內容以下:json

const devConfig = {
    chainWebpack: config => {
        config.module
            .rule('js')
            .include
            .add('/packages')
            .end()
            .use('babel')
            .loader('babel-loader')
            .tap(options => {
                return options
            })
    },
}
複製代碼

以上是開發環境的配置,下面來寫一下生產環境的配置

八、在生產環境下也要將新增的packages文件夾加入babel轉碼編譯

const buildConfig = {
    chainWebpack: config => {
        config.module
            .rule('js')
            .include
            .add('/packages')
            .end()
            .use('babel')
            .loader('babel-loader')
            .tap(options => {
                return options
            })
    },
}
複製代碼

九、配置生產環境構建文件的目錄

咱們將組件庫打包編譯後放在lib文件夾中,在vue.config.js文件中配置內容以下:

const buildConfig = {
    outputDir: 'lib',
}
複製代碼

十、關閉source map

關閉source map有兩個好處

  1. 減小打包編譯的時間;
  2. 避免在生產環境中用F12開發者工具在Sources中看到源碼。

在vue.config.js文件中配置內容以下:

const buildConfig = {
    productionSourceMap: false,
}
複製代碼

3、多入口文件頁面打包配置

在Vue CLI3搭建的項目中藉助babel-plugin-import這個webpack插件而且配置babel.config.js,來實現組件庫的按需引入的前提是組件庫是多入口文件頁面打包的。

一、配置entry

在Vue CLI3中是在configureWebpack選項的entry屬性上配置項目多入口,在本文案例中,配置以下

const buildConfig = {
    configureWebpack: {
        entry: { 
            index: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\index.js',
            testA: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\testA\\index.js',
            testB: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\testB\\index.js' 
        },
    },
}
複製代碼

可是以上每一個入口都是寫死的,因此咱們要利用nodejs實現自動化配置。

首先咱們引入nodejs中path模塊來處理文件路徑。

const path = require('path');
const join = path.join;//拼接路徑
複製代碼

寫一個把目標路徑按當前文件路徑轉成絕對路徑的方法

function resolve(dir) {
    return path.resolve(__dirname, dir)
}
複製代碼

其中__dirname是當前文件所在目錄的完整絕對路徑,例

還要引入nodejs中fs模塊在處理文件信息

const fs = require('fs');
複製代碼

咱們建一個函數getEntries(path),其中path是組件代碼所在的文件夾名稱,返回一個對象entries,key爲每一個組件文件夾的名稱,值爲每一個組件文件夾中入口文件index.js的絕對路徑。

首先使用fs.readdirSync(resolve(path))獲取到組件代碼所在的文件夾目錄下全部文件名稱,存在files變量中。

而後用數組reduce()方法循環files,先將每一個文件名(item)利用join(path, item)轉成路徑存到itemPath變量。

fs.statSync(itemPath).isDirectory()對每一個文件進行判斷是否是文件夾。

若是是文件夾,先把itemPath和入口文件index.js拼接成一個地址,再轉成絕對路徑,將item做爲key,賦值到返回對象上

entries[item] = resolve(join(itemPath, 'index.js'))。
複製代碼

若是不是文件夾,直接把itemPath轉成絕對路徑,將item去除後綴做爲key,賦值到返回對象上

const [name] = item.split('.')
entries[name] = resolve(`${itemPath}`)
複製代碼

下面是完整代碼

function getEntries(path) {
    let files = fs.readdirSync(resolve(path));
    const entries = files.reduce((ret, item) => {
        const itemPath = join(path, item)
        const isDir = fs.statSync(itemPath).isDirectory();
        if (isDir) {
            ret[item] = resolve(join(itemPath, 'index.js'))
        } else {
            const [name] = item.split('.')
            ret[name] = resolve(`${itemPath}`)
        }
        return ret
    }, {})
    return entries
}
複製代碼

好比在本文案例中,執行getEntries('packages')將會獲得一個對象

{ 
    index: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\index.js',
    testA: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\testA\\index.js',
    testB: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\testB\\index.js' 
},
複製代碼

利用對象展開運算符,配置entry

const buildConfig = {
    configureWebpack: {
        entry: { 
            ...getEntries('packages'),
        },
    },
}
複製代碼

二、配置output

  • filename: 配置每一個組件打包後生成對應文件名稱,多入口文件配置爲[name].index.js,爲何配置這個名稱後面會解釋。
  • libraryTarget:配置爲commonjs2,入口文件的返回值將分配給module.exports對象,使其組件庫在webpack構建的環境下使用,這個是關鍵。
const buildConfig = {
    configureWebpack: {
        output: {
            filename: '[name]/index.js',
            libraryTarget: 'commonjs2',
        }
    },
}
複製代碼

三、樣式打包配置

在css.extract.filename上配置樣式打包路徑和文件名稱

const buildConfig = {
    css: {
        sourceMap: true,
        extract: {
            filename: 'style/[name].css'//在lib文件夾中創建style文件夾中,生成對應的css文件。
        }
    },
}
複製代碼

四、刪除Vue CLI3原先打包編譯的一些無用功能

  • 刪除splitChunks,由於每一個組件是獨立打包,不須要抽離每一個組件的公共js出來。
  • 刪除copy,不要複製public文件夾內容到lib文件夾中。
  • 刪除html,只打包組件,不生成html頁面。
  • 刪除preload以及prefetch,由於不生成html頁面,因此這兩個也沒用。
  • 刪除hmr,刪除熱更新。
  • 刪除自動加上的入口App。
const buildConfig = {
    chainWebpack: config => {
        config.optimization.delete('splitChunks')
        config.plugins.delete('copy')
        config.plugins.delete('html')
        config.plugins.delete('preload')
        config.plugins.delete('prefetch')
        config.plugins.delete('hmr')
        config.entryPoints.delete('app')
    },
}
複製代碼

五、配置字體的loader

const buildConfig = {
    chainWebpack: config => {
        config.module
            .rule('fonts')
            .use('url-loader')
            .tap(option => {
                option.fallback.options.name = 'static/fonts/[name].[hash:8].[ext]'
                return option
            })
    },
}
複製代碼

4、組件庫開發

本案例中簡單寫了testA和testB兩個組件來供測試

一、packages目錄結構

主要講一下組件入口文件怎麼編寫,其它跟平時開發同樣。

二、單個組件入口

以組件testA爲例,對外暴露一個對象test,並提供 install 方法,外部就能夠經過Vue.use()來調用這個組件。

import test from './src/index.vue';
test.install = function(Vue) {
    Vue.component(test.name, test);
};
export default test;
複製代碼

三、組件庫總入口

import testA from './testA'
import testB from './testB'
export default {
    install(Vue) {
        Vue.use(testA);
        Vue.use(testB)
    },
}
複製代碼

5、編譯打包

執行npm run build,打包編譯後,在項目中會獲得一個lib文件夾,內容如圖所示。

6、npm發佈前準備工做

一、配置主入口文件

在package.json文件中寫入:

"main": "lib/tree-select.umd.min.js",
複製代碼

二、其餘配置

能夠參考Vue CLI3搭建組件庫並用npm發佈實戰操做

7、按需引入配置

一、引入組件

發佈好後(若是不會發布請看Vue CLI3搭建組件庫並用npm發佈實戰操做),在引用組件庫demo中,執行npm install map-lib-test@0.6.0 --save安裝組件庫。

在執行npm install babel-plugin-import --save-dev安裝babel-plugin-import插件,利用它實現組件按需引入。

在根目錄下babel.config.js文件中按以下配置

module.exports = {
    "presets": ["@vue/app"],
    "plugins": [
        [
            "import",
            {
                "libraryName": "map-lib-test",//組件庫名稱
                "camel2DashComponentName": false,//關閉駝峯自動轉鏈式
                "camel2UnderlineComponentName": false//關閉蛇形自動轉鏈式
            }
        ],
    ]
}

複製代碼

在main.js寫入

import { testA, testB } from 'map-lib-test';
Vue.use(testA);
Vue.use(testB);
複製代碼

在src/views/demo.vue引用

<template>
    <div>
        <testA></testA>
        <testB></testB>
    </div>
</template>
<script>
export default {
    data() {
        return {
        }
    },
}
</script>
複製代碼

瀏覽器展現

二、引入樣式

這裏只知道引入全局樣式。配置按需引入樣式時,總是提示樣式沒法找到,若是有人知道怎麼配置,懇請在評論留言並完善。

從node_modules/_map-lib-test@0.6.0@map-lib-test文件中能夠看到組件庫的結構

故在main.js寫入

import "map-lib-test/lib/style/index.css";
複製代碼

瀏覽器展現

8、注意點

一、 爲何是import{testA,testB}而不是import{testC,testD}

若是是`import {testC ,testD }`,會發生以下報錯
複製代碼

import { testA, testB } from 'map-lib-test';
複製代碼

至關

import testA from  "map-lib-test/lib/testA";
import testB from  "map-lib-test/lib/testB";
複製代碼
import { testC, testD } from 'map-lib-test';
複製代碼

至關

import testC from  "map-lib-test/lib/testC";
import testB from  "map-lib-test/lib/testD";
複製代碼

map-lib-test/lib中沒有testC、testD這個文件,因此就報以上錯誤。

那爲何是import{testA , testB},還記得在多入口文件頁面打包配置中配置entry時,entry對象每一個key是每一個組件代碼所在的文件夾名,而output.filename是'[name]/index.js'。每一個組件是獨立打包,打包生成文件夾名稱是原來每一個組件代碼所在文件夾名稱。

這樣是否是很清楚,爲何要import{testA , testB},是由於testA和testB兩組件打包生成文件夾名分別是testA和testB。

以上還能夠說明爲何output.filename是'[name]/index.js'而不是'[name]/main.js'或者而不是'[name]/out.js'

由於import testA from "map-lib-test/lib/testA";默認至關import testA from "map-lib-test/lib/testA/index.js";

因此在寫組件使用文檔時,必定要寫明按需引入時,是import{testA , testB}的。

二、組件標籤

爲何是<testA></testA>,而不是<testD></testD>。 看一下testA組件的入口文件中有寫這麼一段代碼

import test from './src/index.vue';
test.install = function(Vue) {
    Vue.component(test.name, test);
};
複製代碼

在Vue中註冊以test.name爲名稱的組件,而test.name就是testA組件中name選項的值。

相關文章
相關標籤/搜索