评论

Vue项目使用kbone打包成小程序的踩坑笔记

已有的Vue项目使用kbone只需通过简单的配置即可打包成小程序的代码,新项目也可以使用这个工具进行同步开发

以下内容是初版kbone的笔记,现在kbone进行了大量的更新升级,以下配置方法大部分已经不适用新版kbone了,如需详细了解kbone的使用方法,请参考官方文档

kbone是大佬 @June 开发的一款Vue项目打包成小程序的工具(暂时只支持微信小程序)

已有的Vue项目只需通过简单的配置即可打包成小程序的代码,新项目也可以使用这个工具进行同步开发,项目中提供了很多示例供参考

Github连接:https://github.com/wechat-miniprogram/kbone

为什么选择kbone?

市面上有很多跨平台的框架,如: WePY、mpvue、uni-app、taro等
他们都有一些弊端和限制,现有的项目迁移不方便,对第三方组件库不兼容等

kbone作为一款工具,也可以说是一款webpack插件(Vue项目只需要引入 mp-webpack-plugin 插件,通过简单的webpack配置即可),无论是对新项目还是已有项目都是非常友好的,因为他完整的移植了Vue Runtime,通过webpack将Vue代码打包成小程序兼容的代码,通过适配器运行,所以大部分的第三方组件库是兼容的

如何使用?

Github仓库中提供了很多示例,有兴趣的可以体验下,下面介绍下我的使用过程

创建项目

因为习惯了使用Vue Cli,所以我选择使用这个工具初始化一个项目,使用的版本是Vue Cli 3(这个工具提供了一套完全图形化的用户界面,这里就不介绍使用方法了,没有使用过的同学可以 点击这里 查看创建方法)

集成插件

kbone目前还没有提供Vue Cli的插件(大佬很忙,有能力的同学可以在Github上提PR),所以需要手动添加,具体的操作方式请参考QuickStart文档

安装 mp-webpack-plugin 插件

yarn add mp-webpack-plugin --dev
# 或者
npm install mp-webpack-plugin --save-dev

在 src 目录中新增 main.mp.js 入口文件

import Vue from 'vue'
import App from '@/App'
import router from '@/router'
import store from '@/store'

// 需要将创建根组件实例的逻辑封装成方法
export default function createApp () {
  // 在小程序中如果要注入到 id 为 app 的 dom 节点上,需要主动创建
  const container = document.createElement('div')
  container.id = 'app'
  document.body.appendChild(container)

  Vue.config.productionTip = false

  return new Vue({
    router,
    store,
    render: h => h(App)
  }).$mount('#app')
}

在根目录创建 miniprogram.config.js 文件,添加 mp-webpack-plugin 插件配置

module.exports = {
  // 页面 origin,默认是 https://miniprogram.default
  origin: '', // 填写项目中的图片资源地址,建议图片资源使用线上地址
  // 入口页面路由,默认是 /
  entry: '/',
  // 页面路由,用于页面间跳转
  router: {
    // 路由可以是多个值,支持动态路由
    index: []
  },
  // 特殊路由跳转
  redirect: {
    // 跳转遇到同一个 origin 但是不在 router 里的页面时处理方式,支持的值:webview - 使用 web-view 组件打开;error - 抛出异常;none - 默认值;什么都不做,router 配置项中的 key
    notFound: 'index',
    // 跳转到 origin 之外的页面时处理方式,值同 notFound
    accessDenied: 'index'
  },
  // app 配置,同 https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#window
  app: {
    navigationStyle: 'custom' // 自定义navigation
  },
  // 全局配置
  global: {},
  // 页面配置,可以为单个页面做个性化处理,覆盖全局配置
  pages: {},
  // 优化
  optimization: {
    domSubTreeLevel: 5, // 将多少层级的 dom 子树作为一个自定义组件渲染,支持 1 - 5,默认值为 5

    // 对象复用,当页面被关闭时会回收对象,但是如果有地方保留有对象引用的话,注意要关闭此项,否则可能出问题
    elementMultiplexing: true, // element 节点复用
    textMultiplexing: true, // 文本节点复用
    commentMultiplexing: true, // 注释节点复用
    domExtendMultiplexing: true, // 节点相关对象复用,如 style、classList 对象等

    styleValueReduce: 5000, // 如果设置 style 属性时存在某个属性的值超过一定值,则进行删减
    attrValueReduce: 5000 // 如果设置 dom 属性时存在某个属性的值超过一定值,则进行删减
  },
  // 项目配置,会被合并到 project.config.json
  projectConfig: {
    appid: '', // 填写小程序的AppId
    projectname: '' // 填写小程序的项目名称
  },
  // 包配置,会被合并到 package.json
  packageConfig: {
    name: '', // 项目名称
    description: '', // 描述
    author: '' // 作者信息
  }
}

在根目录创建 .env.mp 文件,添加 mp 环境变量

NODE_ENV = mp

修改 vue.config.js 文件,添加打包小程序的 webpack 配置

const path = require('path')
function resolve (dir) {
  return path.join(__dirname, dir)
}
const webpack = require('webpack')
const MpWebpackPlugin = require('mp-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  css: {
    extract: true
  },
  outputDir: process.env.NODE_ENV === 'mp' ? './dist/mp/common' : './dist/web',
  configureWebpack: {
    resolve: {
      extensions: ['*', '.js', '.vue', '.json'],
      alias: {
        'vue$': 'vue/dist/vue.esm.js',
        '@': resolve('src')
      }
    }
  },
  chainWebpack: config => {
    if (process.env.NODE_ENV === 'mp') {
      config
        .devtool('node')

        .entry('app').clear().add('./src/main.mp.js').end()

        .output.filename('[name].js')
        .library('createApp')
        .libraryExport('default')
        .libraryTarget('window').end()

        .target('web')

        .optimization.runtimeChunk(false)
        .splitChunks({
          chunks: 'all',
          minSize: 1000,
          maxSize: 0,
          minChunks: 1,
          maxAsyncRequests: 100,
          maxInitialRequests: 100,
          automaticNameDelimiter: '~',
          name: true,
          cacheGroups: {
            vendors: {
              test: /[\\/]node_modules[\\/]/,
              priority: -10
            },
            default: {
              minChunks: 2,
              priority: -20,
              reuseExistingChunk: true
            }
          }
        }).end()

        .plugins.delete('copy').end()

        .plugin('define').use(new webpack.DefinePlugin({
          'process.env.isMiniprogram': process.env.isMiniprogram // 注入环境变量,用于业务代码判断
        })).end()

        .plugin('extract-css').use(new MiniCssExtractPlugin({
          filename: '[name].wxss',
          chunkFilename: '[name].wxss'
        })).end()

        .plugin('mp-webpack').use(new MpWebpackPlugin(require('./miniprogram.config.js'))).end()
    }
  }
}

修改 package.json 中的 scripts 属性,添加用于开发和打包的任务

# 开发
"mp-serve": "vue-cli-service build --watch --mode mp"
# 打包
"mp-build": "vue-cli-service build --mode mp"

配置完成,尽情玩耍吧!

目前已知的问题

小程序中无法支持 getComputedStyle 和 getBoundingClientRect 的同步接口,只能异步,所以依赖这两个方法的第三方库,需要进行改造

因为大佬很忙目前还处于开发阶段,很多组件还没有适配,有能力和有精力的同学欢迎去Github提PR

再次奉上Github连接:https://github.com/wechat-miniprogram/kbone

最后一次编辑于  2019-12-10  
点赞 5
收藏
评论

4 个评论

  • 陈式坚
    陈式坚
    2019-08-01

    有没有真实项目,想体验一下

    2019-08-01
    赞同 2
    回复
  • JIM
    JIM
    2019-09-19

    Kbone好像没有支持vuex,请问是不是这样?

    如果不支持,那么有没有办法在使用了kbone的vue项目里调用globalData?

    或者使用类似sessionStorage的存储?

    谢谢!


    2019-09-19
    赞同 1
    回复
  • 拾忆
    拾忆
    2019-07-25

    大佬头发还很茂盛,可以催催大佬努力加加班搞搞。

    2019-07-25
    赞同 1
    回复
  • 连胜
    连胜
    2019-07-26

    话说,微信小程序团队应该早点儿出这工具吧,2年多了,现在才想起来?

    当然,@,我还是要手动给你点赞~

    2019-07-26
    赞同
    回复 3
    • Stephen
      Stephen
      2019-07-26
      可能需求太多做不完吧
      2019-07-26
      回复
    • Stephen
      Stephen
      2019-07-26
      缺人
      2019-07-26
      回复
    • 连胜
      连胜
      2019-07-26回复Stephen

      缺人主是主要原因,说明这个需求级别不高

      2019-07-26
      回复
登录 后发表内容