Webpack打包arcgis js api 3.x纯html+JS+CSS项目

news2024/11/15 13:22:04

需求

小项目。纯HTML+JS+CSS已经部署上线,但是没有做混淆加密,需要进行混淆加密

分析

目前代码里面需要混淆加密的有main.js,其他的不用混淆加密。所以只需要对main.js进行混淆加密就可,但是要保证混淆加密之后能够访问方法。由于目前在index.html的script使用import导入main.js里面的方法,需要有名字,但是打包之后一般会报错找不到这个名字的模块,因为不是从html里面的script进行打包的,所以在script里面引入打包后的main.js(bundle.js)是不会引入成功的因为模块方法变了。因为做了变量名混淆。所以把html script方法放到main.js里面。

实践

入口文件在libs/mian.js 最终webpack打包代码,其中有两个关键点:
1. path: path.resolve(__dirname, ‘a-dist’),// 自定义明明,因为要推到服务器,所以不使用dist命名;
2. TerserPlugin中的混淆取消,只用去除console和代码注释,不能将混淆打开,否则会报错,和另一个混淆工具冲突;

// webpack.config.js
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
// 加密
const WebpackObfuscator = require('webpack-obfuscator');



module.exports = {
    entry: './libs/main.js',
    mode: 'production',
    output: {
        filename: 'bundle.js',
        // libraryTarget: 'amd', // 不用这样设置。因为改了引入esri js api模块的方式,不用AMD方式,改用esri-loader的自定义loadModules。原理是动态加载,避开由于使用require找不到对应模块的问题
        path: path.resolve(__dirname, 'a-dist'),// 自定义明明,因为要推到服务器,所以不使用dist
    },
    devtool: 'source-map',
    devServer: {
        // contentBase: path.join(__dirname, ''),
        compress: true,
        port: 8080,
        open: true, historyApiFallback: {
            index: 'index.html',
        },
    },
    optimization: {
        minimizer: [
            new TerserPlugin({
                terserOptions: {
                    // mangle: true, // 是否混淆变量名,默认为 true。因为引入了WebpackObfuscator,先注释
                   compress: {
                        // 压缩选项
                        drop_console: true, // 是否去除控制台输出,默认为 false
                        drop_debugger: true, // 是否去除调试语句,默认为 false
                    },
                    output: {
                        beautify: false, // 是否美化输出,默认为 false
                        comments: false, // 是否保留注释,默认为 true
                    },
                    // 更多选项请参考 Terser 文档
                },
            }),
        ],
    },
    plugins: [
        new ProgressBarPlugin(),
        new HtmlWebpackPlugin({
            template: 'index.html',  // 指定HTML模板文件的路径
            filename: 'index.html' // 生成的HTML文件名,默认为index.html
            // 还可以添加其他配置选项,如title、favicon等
        }),
        new CopyWebpackPlugin({
            patterns: [
                { from: 'img', to: 'img' },
                { from: 'static', to: 'static' },
                {
                    from: 'libs', to: 'libs', filter: (resourcePath) => {
                        // 在这里添加你想要忽略的文件或目录的逻辑判断。因为我的项目结构原因,打包时候不能把main.js也复制过去,排除掉。
                        return !resourcePath.endsWith('main.js') && !resourcePath.endsWith('map-action.js');
                    }/* globOptions: {
                        ignore: ['libs/main.js', 'libs/map-action.js'] // 设置要忽略的文件或目录的匹配模式
                    } */
                }, // 指定要拷贝的文件或目录,从来源路径到目标路径
                // 可以继续添加其他的规则
            ],
        }),
        // 目前没有和TerserPlugin方法混淆,因为terserOptions中的mangle没有设置以为true
        new WebpackObfuscator({
            rotateUnicodeArray: true,// 启用 Unicode 数组的字符旋转。默认值为 true
            compact: true,// 合并和混淆输出代码。默认值为 true。
            selfDefending: true,// 生成自保护的混淆代码。默认值为 true。
            stringArray: true,// 启用字符串数组混淆。默认值为 true。
            stringArrayEncoding: ['base64', 'rc4'],// 指定字符串数组的编码方式。可选值为 'base64'、'rc4' 和 'none'。默认值为 'base64'。
            
        }),
    ],
    // externals: {
    //     esri: 'esri', // 注意不用在这里在引入一次
    // },

    module: {
        rules: [
            // JS 文件的加载器
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: 'babel-loader',
            },
            // CSS 文件的加载器
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
        ],
    },
};

打包结束在这里插入图片描述

难点

Webpack打包原理中会解析模块引入语句,如import、require找到对应模块,但是esri在html+JS+CSS获取是通过require获取动态链接。问题来了,那为什么一开始arcgis js用require来请求?为什么不用import?但是一般情况下引入require是没有这个方法的,那require从哪里来的?参考:ArcGIS api for js中的require()究竟是什么。得出require()方法从init.js里面来。
为了配合webpack打包,不能使用require()进行加载esri模块,换种方式请求!查了一下集成和请求模块方式,发现有esri-loader,其中有个方法loadModules。如下代码
esri-loader原理

esri-loader具体原理如下(ChatGPT 3.5的回答):

  1. 动态加载:esri-loader 使用动态脚本加载技术来加载 ArcGIS API for
    JavaScript。它会根据用户的需求,在运行时动态地向 HTML 页面中插入<script>标签,从指定的 CDN或本地目录加载相关的 JavaScript 文件。

  2. 异步加载:ArcGIS API for JavaScript 包含多个 JavaScript文件,有些文件可能比较大。为了提高页面加载速度,esri-loader 使用异步加载方式,按需加载所需的文件。这样可以避免一次性加载整个 API,而只加载需要的部分。

  3. 回调处理:当相关 JavaScript 文件加载完成后,esri-loader 会触发用户指定的回调函数。在回调函数中,您可以安全地使用ArcGIS API for JavaScript 的模块和类。

  4. 模块导入:esri-loader 通过自定义的 loadModules方法,简化了模块的导入过程。它允许您以数组形式传入需要导入的模块名,并返回 Promise 对象。当这些模块加载完成后,Promise才会被解析,您就可以在回调函数中使用这些模块

>./libs/main.js esri 地图初始化
import * as esriLoader from './esri-loader/esm/esri-loader.js';
export async function initMap(data) {
    // require和function中的参数必须对应
    console.log("🚀 ~ file: main.js:696 ~ initMap ~ window.$esriLocal:", window.$esriLocal)
    // 必须这样判断,如果html引入了,那这里不用引入,但是似乎会有问题
   // if (!esriLoader.isLoaded()) {
      //  esriLoader.loadScript({ url: "https://js.arcgis.com/3.44/" })
     //   esriLoader.loadCss("https://js.arcgis.com/3.44/esri/css/esri.css")
    // 原来是require,改为loadModules,这样webpack打包时候就不会解析require,也不用在webpack.config.js external里面配置了。参考官方:
    esriLoader.loadModules([
        "esri/map",
        "esri/Color",
        "esri/graphic",
        "esri/geometry/Extent",
        "esri/geometry/Point",
        "esri/geometry/Polygon",
        "esri/geometry/Polyline",
        "esri/SpatialReference",
        "esri/layers/KMLLayer",
        "esri/layers/GraphicsLayer",
        "esri/symbols/SimpleMarkerSymbol",
        "esri/symbols/FillSymbol",
        "esri/symbols/LineSymbol",
        "esri/symbols/SimpleFillSymbol",
        "esri/symbols/SimpleLineSymbol",
        "esri/symbols/TextSymbol",
        "dojo/parser",
        "esri/layers/TileInfo",
        "esri/layers/WebTiledLayer",
        "dojo/dom-style",
        "esri/config"]).then(function ([
            Map, 
            Color, 
            Graphic, 
            Extent, 
            Point, 
            Polygon, 
            Polyline,
            SpatialReference,
            KMLLayer, 
            GraphicsLayer, 
            SimpleMarkerSymbol,
            FillSymbol,
            LineSymbol,
            SimpleFillSymbol,
            SimpleLineSymbol,
            TextSymbol,
            parser, TileInfo, WebTiledLayer, domStyle,
            esriConfig]) {
            window.$esriLocal = {
                Map: Map,
                Color: Color,
                SpatialReference: SpatialReference,
                Extent: Extent,
                WebTiledLayer: WebTiledLayer,
                TileInfo: TileInfo,
                Graphic: Graphic,
                Point: Point,
                Polyline: Polyline,
                GraphicsLayer: GraphicsLayer,
                SimpleMarkerSymbol: SimpleMarkerSymbol,
                FillSymbol: FillSymbol,
                LineSymbol: LineSymbol,
                SimpleFillSymbol: SimpleFillSymbol,
                SimpleLineSymbol: SimpleLineSymbol,
                TextSymbol: TextSymbol,
            }

            //  else {
            console.log("🚀 ~ file: main.js:342 ~ initMap ~ window.$esriLocal:", window.$esriLocal)
            /** 当前地图视角的显示矩形范围*/
            let extentp = { west: 125.9738504337227, south: 61.624205573999646, east: 116.55005559052246, north: 38.67104274606849 };
            let extent = new window.$esriLocal.Extent({
                xmax: extentp.east,
                xmin: extentp.west,
                ymax: extentp.north,
                ymin: extentp.south,
                spatialReference: { wkid: 4490 },
            });
            map = new window.$esriLocal.Map("map", {
                center: [],
                zoom: 1,
                fadeOnZoom: true,
                fitExtent: true,
                sliderPosition: "bottom-right",
                logo: false,// 去除官方logo
                // slider:false,
            });
            // 定位到范围
            map.setExtent(extent);
            // 在这里添加自定义底图
        });
    //}
    // 老方法,但是这样在webpack中会影响打包,因为webpack默认使用commonjs模块系统进行打包,找不到对应模块和包就会报错。
   /*  await require([
        "esri/map",
        "esri/Color",
        "esri/graphic",
        "esri/geometry/Extent",
        "esri/geometry/Point",
        "esri/geometry/Polygon",
        "esri/geometry/Polyline",
        "esri/SpatialReference",
        "esri/layers/KMLLayer",
        "esri/layers/GraphicsLayer",
        "esri/symbols/SimpleMarkerSymbol",
        "esri/symbols/FillSymbol",
        "esri/symbols/LineSymbol",
        "esri/symbols/SimpleFillSymbol",
        "esri/symbols/SimpleLineSymbol",
        "esri/symbols/TextSymbol",
        "dojo/parser",
        "esri/layers/TileInfo",
        "esri/layers/WebTiledLayer",
        "dojo/dom-style",
        "esri/config",
        "dijit/layout/BorderContainer",
        "dijit/layout/ContentPane",
    ], function (
        Map, Color, Graphic, Extent, Point, Polygon, Polyline,
        SpatialReference, KMLLayer, GraphicsLayer, SimpleMarkerSymbol,
        FillSymbol,
        LineSymbol,
        SimpleFillSymbol,
        SimpleLineSymbol,
        TextSymbol,
        parser, TileInfo, WebTiledLayer, domStyle,
        esriConfig
    ) {
        window.$esriLocal = {
            Map: Map,
            Color: Color,
            SpatialReference: SpatialReference,
            Extent: Extent,
            WebTiledLayer: WebTiledLayer,
            TileInfo: TileInfo,
            Graphic: Graphic,
            Point: Point,
            Polyline: Polyline,
            GraphicsLayer: GraphicsLayer,
            SimpleMarkerSymbol: SimpleMarkerSymbol,
            FillSymbol: FillSymbol,
            LineSymbol: LineSymbol,
            SimpleFillSymbol: SimpleFillSymbol,
            SimpleLineSymbol: SimpleLineSymbol,
            TextSymbol: TextSymbol,
        }

        //  else {
        console.log("🚀 ~ file: main.js:342 ~ initMap ~ window.$esriLocal:", window.$esriLocal)
        /** 当前地图视角的显示矩形范围*
        let extentp = { west: 125.9738504337227, south: 61.624205573999646, east: 116.55005559052246, north: 38.67104274606849 };
        let extent = new window.$esriLocal.Extent({
            xmax: extentp.east,
            xmin: extentp.west,
            ymax: extentp.north,
            ymin: extentp.south,
            spatialReference: { wkid: 4490 },
        });
        map = new window.$esriLocal.Map("map", {
            center: [],
            zoom: 1,
            fadeOnZoom: true,
            fitExtent: true,
            sliderPosition: "bottom-right",
            logo: false,// 去除官方logo
            // slider:false,
        });
        // 定位到范围
        map.setExtent(extent);
        // }

    }) */

}

缺点

也算优点吧,就是每次修改代码生效就需要用webpack的devServer进行了,不能用直接访问文件的形式。

注意

可能会出现multipleDefine的错误。就是引入init.js多次,引入一次就够了,还有网上说是jquery,但是我代码里面没用用jQuery,之前也出现了multipleDefine,但是设置这个之后就没有出现了,后面我又用html引入init.js,发现又没有报错,下次报错了再补充(主要没有发现哪里导致重复多次定义,init.js也就引用一次。

另一个猜想,是因为webpac之前有一篇文章说打包成amd,就是这个参数libraryTarget,然后在手机上出现multipleDefine,去除了重新打包就没有报错,这一快比较模糊。)

知识储备

解决这个问题需要的知识储备为

  1. JavaScript模块系统;
  2. webpack原理;
  3. webpack、arcgis js api使用经验;

总结

从原则、框架逻辑开始,也就是各家官方网站库使用教程开始,一般都有前言,包括背景介绍、库开发注意事项、如何使用(继承方式)
ArcGIS Maps SDK for JavaScript
在这里插入图片描述
webpack-getting-started在这里插入图片描述

体系化知识的必要性。碎片化学习只在体系化学习之后。
你要学一个新东西,就要问这个东西是什么?历史是什么?怎么用?目前能用在哪里?基础内容都有什么?
没有具体老师的时候,官方就是最好的老师。

后记

webpack可以修改模块系统标识,所以有人一开始就使用AMD模块开发,修改难度比较难的话就用

libraryTarget: ‘amd’

但是我没时间测试,所以有人可以可以丢链接给我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/706511.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#中的自定义组件(单一组件和复杂组件)

简单的应用程序开发可能不必要制作组件&#xff0c;C#中丰富的组件足以应对绝大多数的开发设想。 稍微复杂一些的应用开发&#xff0c;或者平台开发&#xff0c;或者团队开发&#xff0c;不可避免地要涉及到基础库的搭建&#xff0c;其中会有很多用户组件的设计与开发。 组件分…

计算机视觉 - 理论 - 从卷积到识别

计算机视觉 - 理论入门 前言一&#xff0c;导论&#xff1a;二&#xff0c;卷积&#xff1a;图像去噪&#xff1a;常值卷积&#xff1a;高斯卷积&#xff1a;椒盐去噪&#xff1a;锐化程度&#xff1a; 三&#xff0c;边缘检测&#xff1a;图像信号导数&#xff1a;求导算子:图…

计算机网络-网络层上篇

目录 一、网络层概述 二、网络层提供的两种服务 &#xff08;一&#xff09;面向连接的虚电路服务 &#xff08;二&#xff09;无连接的数据报服务 &#xff08;三&#xff09;虚电路服务与数据报服务的比较 三、IPv4地址及其应用 &#xff08;一&#xff09;IPv4地址概…

【AI底层逻辑】——篇章4:大数据处理与挖掘

目录 引入 一、大数据概述 二、数据处理的流程&方法 1、数据收集——“从无到有” 2、数据加工——“从有到能用” 3、数据分析 三、大数据改变了什么 往期精彩&#xff1a; 引入 AI的表现依赖大数据。曾经一段时间&#xff0c;对于图像识别的准确率只能达到60%~70…

BUUCTF 还原大师 1

题目描述&#xff1a; 我们得到了一串神秘字符串&#xff1a;TASC?O3RJMV?WDJKX?ZM,问号部分是未知大写字母&#xff0c;为了确定这个神秘字符串&#xff0c;我们通过了其他途径获得了这个字串的32位MD5码。但是我们获得它的32位MD5码也是残缺不全&#xff0c;E903???4D…

Elasticsearch 集群日志收集搭建

Elasticsearch-7.2.0Logstash-7.2.0Kibana-7.2.0-Filebeat-7.6.0 第一台集群内网ip&#xff1a;10.0.0.223 ES配置文件&#xff1a;/es_data/es/elasticsearch-7.2.0/config/elasticsearch.yml ES启动命令&#xff1a;/es_data/es/elasticsearch-7.2.0/bin/elasticsearch cl…

报道|本科专业对收入影响巨大!最高以及最低收入的专业有这些

作者&#xff1a;Aimee Picchi 编者按 本文引用并翻译了发表在美国CBS的最新研究&#xff0c;希望能给刚高考完正在挑选大学以及专业的准大学生们一点帮助哦。 最新的研究发现&#xff0c;一个学生的专业和母校能明显地影响ta毕业四年后的收入水平。HEA Group的调查显示&#x…

Jenkins + gitlab 自动部署

1. 背景 作为后台开发&#xff0c;每次我们开发完或者修改一个bug后都要手动合并&#xff0c;打包或者连接服务器执行打包部署命令&#xff0c;每次手动操作&#xff0c;极大的影响了我们的开发效率&#xff0c;那么有没有一款工具能让我们只需要推送/合并代码到远端就能实现服…

【小沐学Python】Python实现Web服务器(Flask框架扩展:Flask-SQLAlchemy)

文章目录 1、简介2、安装3、开发3.1 数据库连接字符串3.2 SQLAlchemy参数设置3.3 SQLAlchemy字段类型3.4 SQLAlchemy列选项3.5 SQLAlchemy关系选项3.6 SQLAlchemy操作接口 4、代码测试4.1 用户管理4.2 用户角色管理4.3 学生管理4.4 图书管理 结语 1、简介 SQLAlchemy SQLALche…

windows下安装Visual Studio + CMake+OpenCV + OpenCV contrib+TensorRT

目录 1 安装visual studio 2 安装CMake 3 OpenCV源码安装 3.1 OpenCV源码下载 3.2 OpenCV contrib源码下载 3.3 安装OpenCV 3.4 安装OpenCV-crontrib 3.5 VS生成代码 4 环境配置 5 TensorRT安装 5.1 TensorRT安装 5.2 Python下安装TensorRT库 最近在研究windows系统…

Android学习_Mars老师之Mp3视频开发

实现的功能&#xff1a;开发一个可以播放音乐并同步显示歌词文件的APP. 成果展示&#xff1a; 总体设计图&#xff1a; 实现流程图 代码展示&#xff1a; AndroidManifest.xml <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:androi…

信道编码:MATLAB使用卷积编译码函数

信道编码&#xff1a;MATLAB 使用Conv函数 1. 相关函数 在进行卷积编码的过程中&#xff0c;使用的函数是convenc()函数和vitdec()函数&#xff0c;同时需要poly2trellis()函数。 1.1 poly2trellis()函数 先看poly2trellis()函数,用来生成卷积编码所需要的网表。 trellis …

svn commit 用法

转载   原文&#xff1a;https://blog.csdn.net/qq_39790633/article/details/103700391 使用svn进行代码的提交有两种方法&#xff1a;一种是通过TortoiseSVN客户端界面进行提交&#xff0c;另一种是通过svn commit指令提交。 方法一&#xff1a;通过TortoiseSVN客户端界面提…

【Python 随练】文本颜色设置

题目&#xff1a; 文本颜色设置 简介&#xff1a; 在本篇博客中&#xff0c;我们将学习如何在Python中设置文本的颜色。我们将介绍一个常用的库&#xff0c;并提供代码示例来演示不同颜色的设置。 问题分析&#xff1a; 我们需要在Python中设置文本的颜色&#xff0c;以增…

3.2迷宫求解

首先我没 看懂数据结构书上写得迷宫 求解 不过 不重要了 迷宫求解 需要先有个 迷宫 游戏 以下 是 Java写的 控制台迷宫游戏 import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern;public class MazeGameJ {public static void main(St…

云原生|kubernetes|centos7下离线化部署kubesphere-3.3.2---基于kubernetes-1.22.16(从网络插件开始记录)

前言&#xff1a; kubesphere的离线化部署指的是通过自己搭建的harbor私有仓库拉取镜像&#xff0c;完全不依赖于外部网络的方式部署。 我的kubernetes集群是一个单master节点&#xff0c;双工作节点&#xff0c;总计三个节点的版本为1.22.16的集群。 该集群只是初始化完成了…

在Excel当前窗口显示最后一行数据

大家也许都知道Excel工作表中数据行数较多&#xff0c;使用<Ctrl下箭头>组合键可以快速定位最后一行&#xff0c;但是如果数据不是连续的&#xff08;也就是工作表中包含空行&#xff09;&#xff0c;这个方式就只能定位到当前连续数据区域的最后一行。 如下实例代码可以…

Visual Studio2019更改并下载.Net Framework目标框架

一、问题 当使用.net进行开发时&#xff0c;开发的项目与.net framework目标框架会非常密切相关的&#xff0c;所以当vs本地使用的.net framework框架与该项目工程的框架不一致的时候&#xff0c;就可能打开不了当前项目&#xff0c;解决这个问题的方法有&#xff1a; 第一种…

方向导数和梯度

理性认识的三个阶段&#xff1a;定义、判断、推理。 有位博主说过&#xff0c;数学中&#xff0c;定义占60%的内容。 方向导数定义如下&#xff1a; 注意的一点是&#xff1a; 该处的alpha&#xff0c;beta角度关系是alpha beta pi/2。t*cos alpha &#xff0c;t * cos …

两百行代码实现简易点云标注工具

夏天来了非常热&#xff0c;LZ周末不想出去玩&#xff0c;于是乎继之前的图片标注工具利用两个晚上写了一个简单的点云标注工具。该工具基于Qt5.14.2-msvc2017&#xff08;其实LZ的VS版本是2019&#xff0c;似乎兼容&#xff09;平台C语言开发&#xff0c;用到的第三方库为PCL1…