组件库建设--基本框架(从0到1)
开发环境
pc环境:windows webpack:5.3.9 webpack-cli:4.9.1 webpack-dev-server: 4.3.1 【全局安装webpack,webpack-cli,webpack-dev-server】
目录结构
components ui组件
docs 文档库
引入方式
全局引入 通过vue.use引入
创建组件
在src/components目录下新建A目录,在A目录里面新建A.vue
创建index.js,将A.vue导出
注意:name要与组件名称一致,比如A.vue,name也应该是A
import A from './A.vue' export default A 复制代码
全局引入
在src目录下,新建index.js,通过install方法进行注册
import A from './components/A' const components = { A, } const install = (Vue) => { Object.keys(components).map((key) => { const component = components[key] Vue.component(component.name, component) }) } // auto install if (typeof window !== 'undefined' && window.Vue) { install(window.Vue); } const HBirthDay = { install } export default HBirthDay //module.exports.default = module.exports = HBirthDay 复制代码
打包
这里的打包,我们参考element-ui,通过打包成一个js文件,我们在其他项目里面通过vue.use引入
webpack.common.js
/** * 公共配置 */ const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') const { VueLoaderPlugin } = require('vue-loader') const webpack = require('webpack') const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { output: { path: path.join(__dirname, 'node_modules/hbirthday'), // 打包生成文件地址 filename: 'HBirthDay.min.js', // 指定输出文件的名称 libraryTarget: 'umd', library: 'HBirthDay', umdNamedDefine: true }, module: { rules: [ { test: /\.js$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], plugins: ['@babel/plugin-transform-runtime'] } }, exclude: /node_modules/ // 不编译node_modules下的文件 }, { // *.vue test: /\.vue$/, loader: 'vue-loader' }, { // 图片 test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: { loader: 'url-loader', options: { limit: 10 * 1024 // 10kb } } }, // { // test: /\.css$/i, // use: [MiniCssExtractPlugin.loader,"css-loader"], // }, { test: /\.css$/i, use: [ { loader: MiniCssExtractPlugin.loader, options: { esModule: false, publicPath: "../", } }, "css-loader", { loader: 'postcss-loader', options: { postcssOptions: { plugins: [ [ 'postcss-preset-env', ], ], }, }, } ] }, ] }, // 解析路径 resolve: { // 设置src别名 alias: { 'vue': 'vue/dist/vue.esm.js', '@': path.resolve(__dirname, 'src'), }, //后缀名 可以根据需要自由增减 extensions: ['.js', '.vue'] }, plugins: [ new VueLoaderPlugin(), new MiniCssExtractPlugin({ // 类似于 webpackOptions.output 中的选项 // 所有选项都是可选的 filename: 'assets/css/[name].css', chunkFilename: 'assets/css/[id].css', }), new HtmlWebpackPlugin({ filename: 'index.html', // 生成的文件夹名 template: 'public/index.html', // 模板html favicon: 'public/favicon.ico', // 图标 }), new webpack.optimize.ModuleConcatenationPlugin() ] } 复制代码
webpack.dev.js
const webpack = require('webpack') const path = require('path') const { merge } = require('webpack-merge') const common = require('./webpack.common') module.exports = merge(common, { mode: 'development', entry: './src/main.js', // 定义入口文件 devServer: { contentBase: path.join(__dirname, 'dist'), // 告诉服务器内容的来源。仅在需要提供静态文件时才进行配置 compress: true, // 开启压缩 port: 8081, // 端口 hotOnly: true, // 热模块替换,保存页面状态 hot: true, // 自动刷新 open: false, historyApiFallback: { index: '/index.html' //与output的publicPath有关(HTMLplugin生成的html默认为index.html) }, }, devtool: 'source-map', plugins: [ new webpack.HotModuleReplacementPlugin(), // 配合 devServer:hot 使用,自动刷新页面 ] }) 复制代码
webpack.prod.js
const { merge } = require('webpack-merge') const common = require('./webpack.common') const { CleanWebpackPlugin } = require('clean-webpack-plugin') const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); module.exports = merge(common, { mode: 'production', entry: './src/index.js', // 定义入口文件 externals: { vue: { root: 'Vue', commonjs: 'vue', commonjs2: 'vue', amd: 'vue' } }, plugins: [ new CleanWebpackPlugin(), new CssMinimizerPlugin(), ] }) 复制代码
package.json
{ "name": "hbirthday", "version": "1.0.0", "description": "生日", "main": "dist/HBirthDay.min.js", "scripts": { "dev": "webpack serve --config webpack.dev.js", "build": "webpack --config webpack.prod.js" }, "keywords": [], "author": "hhh", "license": "ISC", "devDependencies": { "@babel/core": "^7.14.3", "@babel/plugin-transform-runtime": "^7.14.3", "@babel/preset-env": "^7.14.4", "@vue/cli-plugin-babel": "^4.5.14", "babel-loader": "^8.2.2", "clean-webpack-plugin": "^4.0.0-alpha.0", "css-loader": "^5.2.6", "file-loader": "^6.2.0", "html-webpack-plugin": "^5.3.1", "less": "^4.1.1", "less-loader": "^9.1.0", "style-loader": "^2.0.0", "url-loader": "^4.1.1", "vue-loader": "^15.9.7", "vue-style-loader": "^4.1.3", "vue-template-compiler": "^2.6.14", "webpack": "^5.38.1", "webpack-cli": "^4.7.2", "webpack-dev-server": "^3.11.2", "webpack-merge": "^5.8.0" }, "dependencies": { "babel-plugin-components": "^1.0.4", "chalk": "^4.1.1", "compression-webpack-plugin": "^9.0.0", "css-minimizer-webpack-plugin": "^3.1.1", "fa": "^1.0.1", "hbirthday": "^1.0.0", "mini-css-extract-plugin": "^2.4.3", "path": "^0.12.7", "postcss-loader": "^6.2.0", "postcss-preset-env": "^6.7.0", "vue": "^2.6.14", "vue-router": "^3.5.1", "vuex": "^3.6.2" } } 复制代码
全局打包命令
npm run build 复制代码
使用方式
npm发布
任务
完成组件库打包,可通过全局引入组件
发布到npm公共库,可通过npm方式引入
操作步骤
在package.json main配置里面写入"dist/HBirthDay.min.js",也就是你刚才打包好的js文件,只一步必须,否则无法引入
npm config set registry registry.npmjs.org/
npm login
npm publish
426错误解决 :blog.csdn.net/weixin_4169…
注意:邮箱必须经过校验,否则会显示登录错误
package.json里面的name在发布时,必须全部小写,不能有大写字母,另外在每次发布需要更改json里面的version,必须与上一次version不一样
检验是否发布成功
npm发布成功使用方法
局部引入
新建webpack.lib.js文件
const fs = require('fs'); const path = require('path'); const { merge } = require('webpack-merge') const common = require('./webpack.common') const { CleanWebpackPlugin } = require('clean-webpack-plugin') const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); const MiniCssExtractPlugin = require('mini-css-extract-plugin') const join = path.join; const resolve = (dir) => path.join(__dirname, dir); /** * @desc 大写转横杠 * @param {*} str */ function upperCasetoLine(str) { let temp = str.replace(/[A-Z]/g, function (match) { return "-" + match.toLowerCase(); }); if (temp.slice(0, 1) === '-') { temp = temp.slice(1); } return temp; } /** * @desc 获取组件入口 * @param {String} path */ function getComponentEntries(path) { let files = fs.readdirSync(resolve(path)); const componentEntries = files.reduce((fileObj, item) => { // 文件路径 const itemPath = join(path, item); // 在文件夹中 const isDir = fs.statSync(itemPath).isDirectory(); const [name, suffix] = item.split('.'); // 文件中的入口文件 if (isDir) { fileObj[upperCasetoLine(item)] = resolve(join(itemPath, 'index.js')) } // 文件夹外的入口文件 else if (suffix === "js") { fileObj[name] = resolve(`${itemPath}`); } return fileObj }, {}); return componentEntries; } module.exports = merge(common, { mode: 'production', entry: getComponentEntries('src/components'), // 输出配置 output: { // 文件名称 filename: '[name]/index.js', path:path.resolve(__dirname,'node_modules/hbirthday/lib'), umdNamedDefine: true, // 构建依赖类型 libraryTarget: 'umd', // 库中被导出的项 libraryExport: 'default', // 引用时的依赖名 library: 'HBirthDay', }, externals: { vue: { root: 'Vue', commonjs: 'vue', commonjs2: 'vue', amd: 'vue' } }, plugins: [ new CleanWebpackPlugin(), new MiniCssExtractPlugin({ // 类似于 webpackOptions.output 中的选项 // 所有选项都是可选的 filename: '[name]/style.css', chunkFilename: '[id]/[id].css', }), new CssMinimizerPlugin(), // new MiniCssExtractPlugin() ] }) 复制代码
这个文件的作用是加载每个组件文件夹里面的index.js,把它们放置在lib文件夹下
组件库里面index.js
import component1 from './src/component1.vue' component1.install = function (Vue) { console.info('component1----install----') Vue.component(component1.name, component1) } export default component1 复制代码
这里导出install方法,到时我们就可以通过use方法引入,当然还有第二种方式,代码如下:
import A from './A.vue' export default A 复制代码
通过这种方式,只能通过Vue.component(componentName, component)方式引入
package.json增加局部打包命令
"build:lib": "webpack --config webpack.lib.js" 复制代码
结果
我们将所有组件都打包在lib目录下,每一个组件目录下都有一个index.js
接下来我们就可以在main.js单独引入这里的文件
注意这里用了use的方法,是因为我们在组件index.js导出时使用了组件.install方法
接下来我们转变一下引入方式,改为如下方式
import {component1} from 'hbirthday' // import '组件对应的css文件' Vue.use(componnent1) 复制代码
在package.json里面增加babel配置,安装babel-plugin-component插件
"babel": { "plugins": [ [ "component", { "libraryName": "hbirthday" } ] ] } 复制代码
结果
作者:hhh11237
链接:https://juejin.cn/post/7031101581604945933