针对需求相似的项目,有一套开发模板,平时开发时就在上面做修改,下面对这套模板做一下简单的总结。以下是使用的框架或工具。

  1. babeljs 编译器。
  2. eslint 做代码检查工具。
  3. vue全家桶 做视图、状态管理、路由。
  4. webpack 打包。
  5. phantomJS 实现预渲染。
  6. 一套通信框架实现androidjs 通信。

项目是内嵌在App中的H5页面。在生成html 资源包后放到设备特定目录下,由App 去读取。其中babeleslintandroidjs 的通信不详述,主要记录一下其他三个方面。

# vue全家桶。

vue 全家桶的使用就是根据官方文档搭建,抽象出业务需要的公共组件来供不同项目使用。引入events,在每个业务初始化的时候实现事件总线,在事件总线上绑定多个常用的事件。

    import events from 'events'
    import _ from 'lodash'

    const eventBus = {}
    _.mixin(eventBus, events.EventEmitter.prototype)

    eventBus.on(eventName, () => {
        // event function
    })

    eventBus.emit(eventName, ...arr)

# webpack打包

  1. 将压缩好的vue.min.jsvue-router.min.jsvuex.min.js 通过concat-files 合并成一个文件,再通过html-webpack-include-assets-plugin 插入到目标html 文件中。
    const concat = require('concat-files')
    concat([
        '/path/to/vue.min.js',
        '/path/to/vue-router.min.js',
        '/path/to/vuex.min.js'
    ], '/path/to/vue.eco.js', (err) => {
        if (err) {
            throw err
        }
        console.log('done')
    })

    // webpack config
    const HtmlWebpackIncludeAssetsPlugin = require('html-webpack-include-assets-plugin')

    ...
    plugins [
        new HtmlWebpackIncludeAssetsPlugin({
            assets: [
                '/path/to/vue.eco.js'
            ],
            append: false
        })
    ]
  1. if-loader 区分不同环境下的代码
  2. html-webpack-plugin 生成多个html。
  3. CommonsChunkPlugin 做公共模块拆分。
  4. expresswebpack-dev-middlewarewebpack-hot-middleware 实现 dev-server 和 hot-reload。

# phantomJS预渲染

在未使用预渲染的时候,进入页面会有一段的白屏时间,此时在加载 js 和渲染 dom 。为了让用户体验更好,提出了预渲染方案。

预渲染方案的功能实际上是在进入页面的时候,使用已经渲染好的静态界面做为白屏阶段的一个补充 (也就是说这个阶段的界面是不能进行交互的,因为js代码并没有被加载)。在vue渲染好了真正的界面的时候,它会在render 阶段用自己渲染好的界面替换之前的静态界面。

界面用webview 载入,在触发webviewonfinish 事件后,切换显示webview 的内容。为了更快呈现UI,就要让webview 尽快触发onFinish 事件,移除页面内的js 内容,改为setTimeout 逐个注入。同时提供静态化的内容,提前提供渲染好的页面。

利用nodejs 操控 phantom ,打开页面,抓取页面内容并写入。

    const phantom = require('phantom')
    const cheerio = require('cheerio')
    const fs = require('fs-sync')
    const minify = require('html-minifier').minify

    (async function() {
        const instance = await phantom.create()
        const page = await instance.createPage()
        const status = page.open(url)
        let htmlContent
        page.evaluate(function() {
            return document.querySelector('xxx').outerHtml
        }).then((html) => {
            htmlContent = html
        })
        let $ = cheerio.load(htmlContent)
        $('.container').attr('id', 'static')
        const staticContent = minify($.html(), {
            removeAttributeQuotes: true,
            removeComments: true,
            collapseWhitespace: true
        })
        const originalHtml = fs.read('xxx')
        $ = cheerio.load('originalHtml')
        $('#app').remove()
        $(staticContent).appendTo('body')
        const scriptSrcArray = []
        const $script = $('script')
        for (let i = 0; i < $script.length; i++) {
            const src = $('script').eq(i).attr('src')
            if (src) {
                scriptSrcArray.push(src)
            }
        }
        const scriptSrcArrayStr = JSON.stringify(scriptSrcArray)
        $('script').remove()
        $(`<script>
            (function(){
                document.querySelector('#static').attr('id', 'app')
                function appendScript(head, src, callback) {
                    const script = document.createElement('script')
                    script.src = src
                    script.charset = 'utf-8'
                    script.async = true
                    const timeout = setTimeout(completed, 120000)
                    script.onload = completed
                    script.onerror = onScriptError
                    function completed() {
                        script.onerror = script.onload = null
                        clearTimeout(timeout)
                        callback()
                    }
                    function onScriptError() {
                        script.onerror = script.onload = null
                        clearTimeout(timeout)
                        console.log('onScriptError')
                    }
                    head.appendChild(script)
                }
                function appendRecursive(head, scriptSrcArray, i) {
                    if (i < scriptSrcArray.length) {
                        appendScript(head, scriptSrcArray[i], function() {
                            appendRecursive(head, scriptSrcArray, i + 1)
                        })
                    }
                }
                setTimeout(function() {
                    appendRecursive(
                        document.getElementsByTagName('head')[0],
                        JSON.parse('${scriptSrcArrayStr}')
                    )
                })
            })
        })()</script>`.replace(/([\r\n]|\s{3,})/g, '')).appendTo('body')

        const preRendered = $.html()
        fs.write(xxx, preRendered)
        page.close()
        ```
Last Updated: 2/24/2020, 9:11:55 PM