Vue cli3 整合SuperMap巧遇js异步加载的坑

最近使用到superMap做三维地图,而项目又分为可视化大屏与后台管理系统两部分,所以项目配置了多入口,然引入cesium依赖就成了问题,在vue cli3 整合Cesium,处理build 时内存溢出问题虽然知道了整合原生的cesium的方法,

但是在实际开发中会发现superMap 官方扩展的接口是无法使用的,必须引入superMap官方重写的cesium.js才可以, 然而superMap官方并提供模块化的开发版本,所以只有使用原生script 引入了

一、使用script 标签加载cesium

于是我分别在public目录下创建了两个html文件


目录结构

分别是admin 和screen,然后在页面中使用<script src="libs/Cesium/Cesium.js"></script>进行js引入,然而测试发现一个奇怪的问题是cli3的多入口。在初始化时会使用默认的index.html页面作为默认入口页面

image.png

image.png

发现我自己增加的script 都没有了。。。这个怎么办?于是想到了document.createElement("script");在vue 初始化的时候去动态加载js
于是引入了如下专门用于异步加载的函数


var Head = document.getElementsByTagName('head')[0], style = document.createElement('style');

//异步加载css,js文件
function linkScript(parm, fn) {
    var linkScript;
    if (/\.css[^\.]*$/.test(parm)) {
        linkScript = document.createElement("link");
        linkScript.type = "text/" + ("css");
        linkScript.rel = "stylesheet";
        linkScript.href = parm;
    } else {
        // debugger
        linkScript = document.createElement("script");
        linkScript.type = "text/" + ("javascript");
        linkScript.src = parm;
    }
    Head.insertBefore(linkScript, Head.lastChild)
    linkScript.onload = linkScript.onerror = function (res) {
        if (fn) fn(res)
    }
}

linkScript("libs/Cesium/Cesium.js");

admin.js中import '../../components/common/js/asyncLoadExtraAssest'引入

这样是可以将cesium加载进来

二、刷新cesium 实例丢失

然而在点击浏览器左上角刷新按钮强制刷新页面时发现cesium在window中的实例丢失了引起了undefined异常


刷新前
刷新后

三、第一种处理方案(原型缓存)

开始我想到了是否是因为刷新后页面间window 上的实例都清除了,于是想到使用Vue的实例原型来缓存第一次加载进来的cesium实例(使用到了函数柯里化来进行cesium缓存)最后发现没有任何作用


函数柯里化缓存cesium

四、第二种处理方案(更改 script 为同步)

再后来打断点一跟发现,


首先引入了cesium js
然后执行到了初始化地图的函数,发现这个时候cesium为空

最后才是cesium.js加载完成

不对其实,window中的cesium实例是存在的只是较晚于页面中加载地图的组件,于是想到了是script 中异步加载解析cesium.js的锅,于是想将script加载解析更改为同步执行;

但是这个想法好像行不通,document加载的script 默认就是异步,就算为其增加 async:false也没用(浏览器会自动屏弃掉)

五、第三种处理方案(使用HtmlWebpackPlugin插件)

于是有想到了使用 HtmlWebpackPlugin为其设置页面配置


修改index.html

增加一个page.json

增加一个mutilPageConfig.js来配置每个页面的属性

const fs = require("fs");
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 通过页面配置文件过去页面json
function generateByConfig() {
    return JSON.parse(fs.readFileSync("./src/page.json"));
}

// 生成extraEntry
const extraEntry = generateByConfig();

let newExtraEntry = {};

// 生成HtmlWebpackPlugin
let extraHtmlWebpackPlugins = [];

for (let i in extraEntry) {
    let chunk = i;
    newExtraEntry[chunk] = extraEntry[i].path;
    extraHtmlWebpackPlugins.push(
        new HtmlWebpackPlugin({
            filename: chunk + ".html",
            template: "public/index.html",
            chunks: [chunk],
            title: extraEntry[i].title,
            favicon:extraEntry[i].favicon,
            iconfont:' <link rel="stylesheet" href="//at.alicdn.com/t/font_1668594_l9pybqe35u.css">',
            widgets:' <link rel="stylesheet" href="libs//Cesium/Widgets/widgets.css">',
            cesium:' <script src="libs/Cesium/Cesium.js"></script>',
        })
    );
};

// 复制静态资源
// extraHtmlWebpackPlugins.push(
//     new CopyWebpackPlugin([
//             {
//                 from: './src/assets/libs',
//                 to: 'libs',
//                 ignore: ['.*']
//             }
//     ])
// )

exports.extraEntry = newExtraEntry;
exports.extraHtmlWebpackPlugins = extraHtmlWebpackPlugins;

vue.config.js引入

const multiBuilder = require("./multiPageConfig");
const { extraEntry, extraHtmlWebpackPlugins } = multiBuilder;

module.exports = {
    configureWebpack: {
        entry: {
            ...extraEntry
        },
        plugins: extraHtmlWebpackPlugins,
     }
}

再删除掉pages相关配置,运行发现提示

 ERROR  Failed to compile with 2 errors                                                                         11:17:52

This relative module was not found:

* ./src/main.js in multi (webpack)-dev-server/client?http://192.168.0.101:8081/sockjs-node (webpack)/hot/dev-server.js ./src/main.js, multi (webpack)/hot/dev-server.js (webpack)-dev-server/client?http://192.168.0.101:8081/sockjs-node ./src/main.js

转念一想,糊涂这是cli2的加载方式,cli3使用的是pages进行配置的,于是我将pages恢复并修改为

修改pages配置

发现
页面title也icon可以加载正确

虽然页面一片空白,但是页面title也icon可以加载正确!

六、最终处理方案(使用pages属性配置外部资源)

有了上面的初步测试发现多个页面可以使用一个index.html,

于是再到vue官网去看看

官网对pages描述

这个比较坑的是平时喜欢使用中文版的

中文翻译是否漏了一段

看中文翻译是否漏了一段 哎,看来英语很重要呀

有了上诉经历,现在基本明白怎么进行接下来的操作了


修改page中的配置来更改页面加载的外部资源,而上一步配置的mutilPageConfig可改下,进行配置整合,再运行发现页面OK了,刷新cesium也不会再丢失了

效果图

最后在完整配置如下


1、page.json

{
  "index": {
    "entry": "./src/views/admin/admin.js",
    "template": "public/index.html",
    "filename": "index.html",
    "favicon": "public/favicon_management.ico",
    "title": "后台管理系统",
    "iconfont":" <link rel='stylesheet' href='//at.alicdn.com/t/font_1668594_l9pybqe35u.css'>",
    "widgets":" <link rel='stylesheet'' href='libs//Cesium/Widgets/widgets.css'>",
    "cesium":" <script type='text/javascript'' src='libs/Cesium/Cesium.js'></script>",
    "chunks": ["chunk-vendors", "chunk-common", "index"]
  },
  "view": {
    "entry": "./src/views/bigScreen/screen.js",
    "emplate": "public/index.html",
    "filename": "view.html",
    "title": "可视化平台",
    "favicon": "public/favicon_view.ico",
    "iconfont":" <link rel='stylesheet' href='//at.alicdn.com/t/font_1668594_l9pybqe35u.css'>",
    "widgets":" <link rel='stylesheet'' href='libs//Cesium/Widgets/widgets.css'>",
    "cesium":" <script type='text/javascript'' src='libs/Cesium/Cesium.js'></script>",
    "chunks": ["chunk-vendors", "chunk-common", "view"]
  }
}

2、multiPageConfig.js

const fs = require("fs");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i;

const isProduction = process.env.NODE_ENV === 'production';

// 生成HtmlWebpackPlugin
let extraHtmlWebpackPlugins = [];
// 复制静态资源
extraHtmlWebpackPlugins.push(
    new CopyWebpackPlugin([
        {
            from: './src/assets/libs',
            to: 'libs',
            ignore: ['.*']
        }
    ])
)
if(isProduction){
    extraHtmlWebpackPlugins.push(
        new UglifyJsPlugin({
            uglifyOptions: {
                compress: {
                    drop_console: true,
                    drop_debugger: false,
                    pure_funcs: ['console.log']//移除console
                }
            },
            sourceMap: false,
            parallel: true
        }),
        new CompressionWebpackPlugin({
            filename: '[path].gz[query]',
            algorithm: 'gzip',
            test: productionGzipExtensions,
            threshold: 10240,
            minRatio: 0.8
        })
    )
}

// 通过页面配置文件过去页面json
function generateByConfig() {
    return JSON.parse(fs.readFileSync("./src/page.json"));
}

// 生成extraEntry
const entryPages = generateByConfig();


exports.extraEntry = entryPages;

exports.extraHtmlWebpackPlugins = extraHtmlWebpackPlugins

3、index.js

const path = require("path");
const multiBuilder = require("./multiPageConfig");
const { extraEntry, extraHtmlWebpackPlugins } = multiBuilder;

const isProduction = process.env.NODE_ENV === 'production';
function assetsPath (_path) {
    const assetsSubDirectory = isProduction ? './': '/';
    return path.posix.join(assetsSubDirectory, _path)
}

module.exports = {
    pages:extraEntry,
    configureWebpack: {
        output: {
            sourcePrefix: ' '
        },
        amd: {
            toUrlUndefined: true
        },
        resolve: {
            // alias: {
            //     'cesium': path.resolve(__dirname, '../',cesiumSource)
            // }
        },
        plugins: extraHtmlWebpackPlugins,
        module: {
            rules: [
                {
                    test: /\.(cur)(\?.*)?$/,
                    loader: 'url-loader',
                    options: {
                        limit: 10000,
                        name: assetsPath('cur/[name].[hash:7].[ext]')
                    }
                },
            ],
            unknownContextCritical: /^.\/.*$/,
            unknownContextCritical: false

        }
    },
    css: {
        loaderOptions: {
            postcss: {
                plugins: [
                    require("postcss-px-to-viewport")({
                        unitToConvert: "px",
                        viewportWidth: 1920,
                        viewportHeight: 960,
                        unitPrecision: 3,
                        propList: ["*"],
                        viewportUnit: "vw",
                        selectorBlackList: ['.ignore', 'calc'],
                        minPixelValue: 1,
                        mediaQuery: false,
                        exclude: /((\/|\\)(node_modules|src)(\/|\\))/,
                    })
                ]
            }
        }
    }
}

4、vue.config.js


const extraConfig = require('./configHelper/index.js')
module.exports = {
    publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
    devServer: {
        port: 8081,
        disableHostCheck: true,
    },
    pages: extraConfig.pages,
    productionSourceMap: false,
    configureWebpack: extraConfig.configureWebpack,
    css: extraConfig.css
}

七、配置SuperMap全局构造

上面说到的将SuperMap重新过的Cesium.js整合到了项目中,也解决了页面刷新异步加载外部js 的问题,但是在全局使用SuperMap构造函数时还是会提示undefined,因为这里还需要将从SuperMap官网下载的

下载后的SuperMap包

中的
SuperMap扩展文件夹

这些扩展文件夹加入到vue的项目中去

1、首先将其拷贝到libs 文件夹下
拷贝到libs中
2、在page.json中新增"superMap":"<script type='text/javascript' src='libs/SuperMap.Include.js'></script>",

如:

新增supermap script
3、在index.html中新增<%= htmlWebpackPlugin.options.superMap %>

如:

index.html修改
4、现在就可以在项目中使用了
组件中使用


OK 到此问题总算解决了,也对js 异步加载和vue多入口配置有了进一步了解,特此记录希望对小伙伴有帮助,感谢你的阅读,如觉得ok请点赞或分享,赠人玫瑰手有余香,你会快乐开心每一天的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • 33、JS中的本地存储 把一些信息存储在当前浏览器指定域下的某一个地方(存储到物理硬盘中)1、不能跨浏览器传输:在...
    萌妹撒阅读 2,083评论 0 2
  • 前言 使用Vue在日常开发中会频繁接触和使用生命周期,在官方文档中是这么解释生命周期的: 每个 Vue 实例在被创...
    心_c2a2阅读 2,253评论 1 8
  • Vue.js作为目前最热门最具前景的前端框架之一,其提供了一种帮助我们快速构建并开发前端项目的新的思维模式。本文旨...
    劳卜阅读 53,415评论 22 420
  • ## 框架和库的区别?> 框架(framework):一套完整的软件设计架构和**解决方案**。> > 库(lib...
    Rui_bdad阅读 2,907评论 1 4
  • 自从有了孩子以后,曾经不屑一顾的育儿文章什么教育理念现在都会眼前一亮,一早看到一篇你的脸色是孩子世界的颜色,又魔性...
    哈哈飞80阅读 109评论 0 1