• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

关于uni-build打包小程序的源码分析

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

  我们使用uni-app的脚手架开发微信小程序其实已经比较方便。但是uni-app框架是怎么实现将vue项目打包成微信小程序项目,很少有人关注。关于uni-build打包小程序的源码分析。底层还是使用的webpack打包框架,uni-app实现了自己的一套算法。针对小程序所要求的文件结构,将VUE项目转换成微信小程序可识别的项目结构。看了一下源码,不是很好读,我接下来主要把找到的编译入口方法展示给大家看下,有需要的朋友可以顺着入口往里解读。

前言

  小程序包含一个描述整体程序的 app 和多个描述各自页面的 page

  一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下:

  
  一个小程序页面由四个文件组成,分别是:

  注意:为了方便开发者减少配置项,描述页面的四个文件必须具有相同的路径与文件名。

https://developers.weixin.qq.com/miniprogram/dev/framework/structure.html

一、打包实现在依赖包vue-cli-plugin-uni中,入口看build.js文件

 uni-build打包的build源码

async function build (args, api, options) {
  const fs = require(\'fs-extra\')
  const chalk = require(\'chalk\')
  const webpack = require(\'webpack\')

  const {
    log,
    done,
    logWithSpinner,
    stopSpinner
  } = require(\'@vue/cli-shared-utils\')

  const runByAliIde = process.env.BUILD_ENV === \'ali-ide\'

  log()

  if (!runByHBuilderX && !runByAliIde) {
    logWithSpinner(`开始编译当前项目至 ${process.env.UNI_SUB_PLATFORM || process.env.UNI_PLATFORM} 平台...`)
  }
  // 解析文件输出目录
  const targetDir = api.resolve(options.outputDir)
  // 获取打包配置文件
  const webpackConfigs = getWebpackConfigs(api, args, options)
  // 生成环境打包,会先清理掉 node_modules/.cache 下的缓存文件
  if (process.env.NODE_ENV === \'production\') {
    try {
      fs.emptyDir(path.resolve(process.env.UNI_CLI_CONTEXT, \'node_modules/.cache\'))
    } catch (e) {}
  }
  // 有clean参数,或者是app-plus打包,则清空输出目录
  if (args.clean || process.env.UNI_PLATFORM === \'app-plus\') {
    await fs.emptyDir(targetDir)
  }

  if (process.env.UNI_USING_NATIVE || process.env.UNI_USING_V3_NATIVE) {
    webpackConfigs.length = 0
  }

  if (
    process.env.UNI_USING_NATIVE ||
    process.env.UNI_USING_V3_NATIVE ||
    (process.UNI_NVUE_ENTRY && Object.keys(process.UNI_NVUE_ENTRY).length)
  ) {
    webpackConfigs.push(require(\'@dcloudio/vue-cli-plugin-hbuilderx/build/webpack.nvue.conf.js\')(process.UNI_NVUE_ENTRY))
  }

  return new Promise((resolve, reject) => {
    webpack(webpackConfigs, (err, stats) => {
      if (!runByHBuilderX && !runByAliIde) {
        stopSpinner(false)
      }
      if (err) {
        return reject(err)
      }

      if (stats.hasErrors()) {
        /* eslint-disable prefer-promise-reject-errors */
        return reject(\'Build failed with errors.\')
      }

      if (!args.silent && (process.env.UNI_PLATFORM !== \'app-plus\' || process.env.UNI_AUTOMATOR_WS_ENDPOINT)) {
        const targetDirShort = path.relative(
          api.service.context,
          process.env.UNI_OUTPUT_DIR
        )

        if (!args.watch) {
          const dirMsg = runByHBuilderX ? \'\'
            : `The ${chalk.cyan(targetDirShort)} directory is ready to be deployed.`
          done(`Build complete. ${dirMsg}`)

          if (process.env.UNI_PLATFORM === \'h5\' && !isInHBuilderX) {
            console.log()
            console.log(\'欢迎将H5站部署到uniCloud前端网页托管平台,高速、免费、安全、省心,详见:\')
            console.log(\'https://uniapp.dcloud.io/uniCloud/hosting\')
          }
        } else {
          const dirMsg = runByHBuilderX ? \'\' : `The ${chalk.cyan(targetDirShort)} directory is ready. `
          done(`Build complete. ${dirMsg}Watching for changes...`)
        }
      }

      resolve()
    })
  })
}
View Code

二、打包微信小程序的代码入口地址

 mp的入口文件index.js中定义了微信小程序打包的相关配置

webpackConfig (webpackConfig, vueOptions, api) {
    if (!webpackConfig.optimization) {
      webpackConfig.optimization = {}
    }
    // disable noEmitOnErrors
    webpackConfig.optimization.noEmitOnErrors = false

    webpackConfig.optimization.runtimeChunk = {
      name: \'common/runtime\'
    }

    webpackConfig.optimization.splitChunks = require(\'../split-chunks\')()

    parseEntry()

    const statCode = process.env.UNI_USING_STAT ? \'import \\'@dcloudio/uni-stat\\';\' : \'\'

    const beforeCode = \'import \\'uni-pages\\';\'

    return {
      mode: process.env.NODE_ENV === \'production\' ? \'production\' : \'development\',
      entry () {
        return process.UNI_ENTRY
      },
      output: {
        filename: \'[name].js\',
        chunkFilename: \'[id].js\',
        globalObject: process.env.UNI_PLATFORM === \'mp-alipay\' ? \'my\' : \'global\'
        // sourceMapFilename: \'../.sourcemap/\' + process.env.UNI_PLATFORM + \'/[name].js.map\'
      },
      performance: {
        hints: false
      },
      resolve: {
        extensions: [\'.nvue\'],
        alias: { // 仅 mp-weixin
          \'mpvue-page-factory\': require.resolve(
            \'@dcloudio/vue-cli-plugin-uni/packages/mpvue-page-factory\')
        }
      },
      module: {
        rules: [{
          test: path.resolve(process.env.UNI_INPUT_DIR, getMainEntry()),
          use: [{
            loader: path.resolve(__dirname, \'../../packages/wrap-loader\'),
            options: {
              before: [
                beforeCode + require(\'../util\').getAutomatorCode() + statCode
              ]
            }
          }, {
            loader: \'@dcloudio/webpack-uni-mp-loader/lib/main\'
          }]
        }, {
          resourceQuery: /vue&type=script/,
          use: [{
            loader: \'@dcloudio/webpack-uni-mp-loader/lib/script\'
          }]
        }, {
          resourceQuery: /vue&type=template/,
          use: [{
            loader: \'@dcloudio/webpack-uni-mp-loader/lib/template\'
          }, {
            loader: \'@dcloudio/vue-cli-plugin-uni/packages/webpack-uni-app-loader/page-meta\'
          }]
        }, createTemplateCacheLoader(api), {
          resourceQuery: [
            /lang=wxs/,
            /lang=filter/,
            /lang=sjs/,
            /blockType=wxs/,
            /blockType=filter/,
            /blockType=sjs/
          ],
          use: [{
            loader: require.resolve(
              \'@dcloudio/vue-cli-plugin-uni/packages/webpack-uni-filter-loader\')
          }]
        }]
      },
      plugins: [
        new WebpackUniAppPlugin(),
        createUniMPPlugin(),
        new webpack.ProvidePlugin(getProvides())
      ]
    }
  },
  chainWebpack (webpackConfig, vueOptions, api) {
    if (process.env.UNI_PLATFORM === \'mp-baidu\') {
      webpackConfig.module
        .rule(\'js\')
        .exclude
        .add(/\.filter\.js$/)
    }

    const compilerOptions = process.env.UNI_USING_COMPONENTS ? {} : require(\'../mp-compiler-options\')

    modifyVueLoader(webpackConfig, {}, compilerOptions, api)

    const styleExt = getPlatformExts().style

    webpackConfig.plugin(\'extract-css\')
      .init((Plugin, args) => new Plugin({
        filename: \'[name]\' + styleExt
      }))

    if (
      process.env.NODE_ENV === \'production\' &&
      process.env.UNI_PLATFORM !== \'app-plus\'
    ) {
      const OptimizeCssnanoPlugin = require(\'../../packages/@intervolga/optimize-cssnano-plugin/index.js\')
      webpackConfig.plugin(\'optimize-css\')
        .init((Plugin, args) => new OptimizeCssnanoPlugin({
          sourceMap: false,
          filter (assetName) {
            return path.extname(assetName) === styleExt
          },
          cssnanoOptions: {
            preset: [
              \'default\',
              Object.assign({}, getPlatformCssnano(), {
                discardComments: true
              })
            ]
          }

        }))
    }

    webpackConfig.plugins.delete(\'hmr\')
    webpackConfig.plugins.delete(\'html\')
    webpackConfig.plugins.delete(\'copy\')
    webpackConfig.plugins.delete(\'preload\')
    webpackConfig.plugins.delete(\'prefetch\')
  }
View Code

三、运行打包前所捕获到的 webpackConfigs 相关参数

[ { mode: \'production\',
    context: \'D:\\02code\\app-wechat-supply\',
    devtool: false,
    node:
     { setImmediate: false,
       process: \'mock\',
       dgram: \'empty\',
       fs: \'empty\',
       net: \'empty\',
       tls: \'empty\',
       child_process: \'empty\' },
    output:
     { path: \'D:\\02code\\app-wechat-supply\\dist\\mit\',
       filename: \'[name].js\',
       publicPath: \'/\',
       chunkFilename: \'[id].js\',
       globalObject: \'global\' },
    resolve:
     { alias: [Object],
       extensions: [Array],
       modules: [Array],
       plugins: [Array] },
    resolveLoader: { modules: [Array], plugins: [Array] },
    module:
     { noParse: /^(vue|vue-router|vuex|vuex-router-sync)$/,
       rules: [Array] },
    optimization:
     { splitChunks: [Object],
       minimizer: [Array],
       noEmitOnErrors: false,
       runtimeChunk: [Object],
       namedModules: false },
    plugins:
     [ VueLoaderPlugin {},
       [DefinePlugin],
       [CaseSensitivePathsPlugin],
       [FriendlyErrorsWebpackPlugin],
       [MiniCssExtractPlugin],
       [OptimizeCssnanoPlugin],
       [HashedModuleIdsPlugin],
       [NamedChunksPlugin],
       [DefinePlugin],
       [CopyPlugin],
       [CopyPlugin],
       WebpackUniAppPlugin {},
       WebpackUniMPPlugin {},
       [ProvidePlugin],
       [CopyPlugin] ],
    entry: [Function: entry],
    performance: { assetFilter: [Function: assetFilter], hints: false } } ]

 四、小程序打包后的项目结构

 参考资料:

https://uniapp.dcloud.io/

https://developers.weixin.qq.com/ebook?action=get_post_info&docid=000668c6910b784b00860870a5ac0a

https://developers.weixin.qq.com/miniprogram/dev/framework/structure.html


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
微信小程序模板消息跳转链接填写发布时间:2022-07-18
下一篇:
小程序反编译,怎么找回微信小程序源码?发布时间:2022-07-18
热门推荐
    热门话题
    阅读排行榜

    扫描微信二维码

    查看手机版网站

    随时了解更新最新资讯

    139-2527-9053

    在线客服(服务时间 9:00~18:00)

    在线QQ客服
    地址:深圳市南山区西丽大学城创智工业园
    电邮:jeky_zhao#qq.com
    移动电话:139-2527-9053

    Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap