npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@supermapgis/webpack-plugin-loadsdk

v1.0.0

Published

Webpack 插件,用于在 Webpack 项目中集成 @supermapgis/clientx 或 @supermapgis/iclient3d。通过 target 参数切换目标包。提供以下功能:1) 自动设置 window.SUPERMAP3D_BASE_URL(用户无需手动设置);2) 自动注入 Widget CSS link 标签;3) dev server 静态资源代理(wasm/worker/图片等);4) 构建后自动复制运行时静态资源到产物目录(支持 glob 过滤);5) 自动配置 re

Readme

@supermapgis/webpack-plugin-loadsdk

用于在 Webpack 项目中一键集成 @supermapgis/clientx@supermapgis/iclient3d 三维 GIS SDK 的官方 Webpack 插件。

npm version License


为什么需要这个插件

@supermapgis/clientx / @supermapgis/iclient3d 是复杂的 WebGL 三维 GIS SDK,其 NPM 包包含两部分:

  • ESM 模块代码SourceRelease/):供打包器按需引入和 tree-shaking
  • 运行时静态资源Build/<assetsDirName>/):WASM 文件、Worker 脚本、纹理图片、Widget CSS 等

直接在 Webpack 项目中使用会面临以下问题,本插件自动完成全部处理:

  1. SDK 运行时通过 window.SUPERMAP3D_BASE_URL 定位静态资源,需手动注入
  2. Widget CSS 需手动引入
  3. dev server 需配置静态资源代理,将 /<assetsDirName>/ 映射到 node_modules
  4. npm run builddist/ 需要包含静态资源,否则部署后页面 404
  5. draco3d 等库引用了 Node.js fs/path 模块,Webpack 5 不再自动 polyfill,需配置 resolve.fallback
  6. 扁平化后部分动态 import() 仍引用原始文件名,Webpack 预解析时报 "Module not found"
  7. 包内部分 bare import 的依赖未安装,Webpack 默认中断构建(esbuild 预打包则会跳过)
  8. 混淆器导出名称不一致导致 "export 'X' was not found" 构建错误
  9. 包内小写路径导入(core/Accessor.js)与实际目录(Core/)大小写不一致,产生 "multiple modules" 警告
  10. dev 模式下 SDK 源码可通过 DevTools 直接调试,缺乏保护

安装

npm install @supermapgis/webpack-plugin-loadsdk @supermapgis/clientx

注意: 需同时在项目根目录 package.json 中配置 overrides 强制依赖版本:

"overrides": {
  "@zip.js/zip.js": "2.7.57",
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz"
}

快速开始

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const SuperMapLoadSDKWebpackPlugin = require('@supermapgis/webpack-plugin-loadsdk');

module.exports = (env, argv) => ({
  entry: './src/index.js',
  output: {
    filename: 'bundle/bundle.js',
    chunkFilename: 'bundle/[name].[contenthash:8].js',
    assetModuleFilename: 'assets/[contenthash][ext][query]',
    publicPath: argv.mode === 'development' ? '/' : './',
    path: path.resolve(__dirname, 'dist'),
    clean: true,
  },
  module: {
    rules: [
      { test: /\.css$/, use: ['style-loader', 'css-loader'] },
      { test: /\.(wasm|hdr|ktx2|terrain|glb|gltf|png|jpg|svg|xml|json)$/, type: 'asset/resource' },
      {
        // SourceRelease 是 ESM 模块,但 import 路径省略了 .js 扩展名,
        // Webpack 5 对 ESM 要求 fully specified,这里关闭它以兼容
        test: /\.m?js$/,
        resolve: { fullySpecified: false },
      },
    ],
    // 禁用 AMD 解析器,避免 sprintfjs 的 "define cannot be used indirect" 错误
    parser: { javascript: { amd: false } },
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './index.html' }),
    new SuperMapLoadSDKWebpackPlugin({ target: 'clientx' }),
  ],
  devServer: {
    // devServer 必须存在,插件在其 static 配置上追加 SDK 资源目录的映射
    static: { directory: path.resolve(__dirname, 'dist') },
    hot: true,
    port: 8085,
    open: true,
  },
  resolve: {
    mainFields: ['module', 'browser', 'main'],
    symlinks: false,
  },
  experiments: {
    asyncWebAssembly: true,
  },
});
// src/index.js
import * as ClientX from '@supermapgis/clientx';

const viewer = new ClientX.Viewer('Container', {});

target 参数

插件通过 target 参数切换目标 SDK 包,内部自动推导 packagePathassetsDirName 等常量:

| target | packagePath | assetsDirName | 入口文件 | |--------|-------------|---------------|----------| | 'clientx'(默认) | @supermapgis/clientx | ClientX | clientx.js | | 'iclient3d' | @supermapgis/iclient3d | SuperMap3D | supermap3d.js |

// 集成 @supermapgis/clientx(默认,可省略 target)
new SuperMapLoadSDKWebpackPlugin({ target: 'clientx' })

// 集成 @supermapgis/iclient3d
new SuperMapLoadSDKWebpackPlugin({ target: 'iclient3d' })

配置项

| 配置项 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | target | 'clientx' \| 'iclient3d' | 'clientx' | 目标 SDK 包,决定 packagePath / assetsDirName 等内部常量 | | packagePath | string | 根据 target 自动推导 | npm 包路径,可显式覆盖 | | assetsDirName | string | 根据 target 自动推导 | 运行时静态资源目录名,可显式覆盖 | | copyFolders | string[] | 见下方 | build 后复制的目录(全量模式生效) | | baseUrl | string | 自动计算 | 覆盖 SUPERMAP3D_BASE_URL,dev 用 /<assetsDirName>/,build 用 ./<assetsDirName>/ | | isAddWidgetCSS | boolean | true | 是否自动注入 Widget CSS link 标签 | | preventDebug | boolean | true | dev 模式下是否禁止调试 SDK 模块,设为 false 可关闭此功能以便排查问题 | | staticAssets | object | { filter: false, keepFiles: [] } | 静态资源复制控制 |

copyFolders 默认值:

['Assets', 'Workers', 'ThirdParty', 'Widgets', 'language', 'ReactiveWidgets', 'SkyAtmosphereSystem']

staticAssets 子选项:

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | filter | boolean | false | false = 全量拷贝 copyFolders 中的所有目录;true = 仅拷贝 keepFiles 匹配的文件 | | keepFiles | string[] | [] | glob 规则列表,路径相对于 Build/<assetsDirName>/,仅在 filter: true 时生效 |

注意: staticAssets.filtertrue 时依赖 glob,该依赖已包含在本插件的 dependencies 中,安装插件时会自动安装,无需手动添加。


插件内部结构

Webpack 插件是一个 Class,通过 apply(compiler) 注册多个钩子,自动完成以下工作:

| 功能 | 钩子 | 作用 | |------|------|------| | 防调试保护 | compiler 初始化 | dev 模式下禁用 SDK 包的 source map,防止用户在 DevTools 中调试 SDK 代码 | | 缺失文件空模块回退 | resolver.hooks.file | 扁平化后悬空 import 的文件不存在时,回退到空模块 _empty_module.js | | bare import 空模块回退 | resolver.hooks.resolve | 目标包内发起的 bare import 无法解析时,回退为空模块并输出 warning | | named export 修复 | module.rules | 混淆器导出名称不一致时降级为警告,不阻断构建 | | 路径大小写规范化 | resolver.hooks.file | 将 core/Accessor.js 规范化为 Core/Accessor.js,消除 multiple modules 警告 | | Node.js polyfill | resolve.fallback | 自动配置 fs: falsepath: false,禁止 Webpack 尝试 polyfill Node.js 核心模块 | | 自动注入 BASE_URL | processAssets | 在 bundle.js 最前面注入 window.SUPERMAP3D_BASE_URL | | dev server 资源代理 | devServer.static | 将 /<assetsDirName>/ 路径映射到 node_modules 中的资源目录 | | build 资源复制 | afterEmit | 将运行时静态资源复制到 dist/<assetsDirName>/(全量或过滤模式) | | Widget CSS 注入 | alterAssetTags | 在 HTML <head> 中插入 <link> 引入 widgets.css |

防调试保护(preventDebug)

解决的问题: Webpack dev 模式默认使用 eval-cheap-module-source-map,模块代码会作为独立文件出现在 DevTools Sources 面板中,用户可以直接查看源码并设置断点。

工作方式(仅 dev 模式,preventDebug: true 时启用):

  1. 设置 compiler.options.devtool = false,禁用 eval 包装,模块代码不再作为独立文件出现
  2. 注册 SourceMapDevToolPlugin,通过 exclude 排除目标包(使用包根路径正则匹配),不为其生成 source map

效果: 用户无法在 DevTools 中查看 SDK 的可读源码或设置有效断点。用户自身的业务代码仍可正常调试。

缺失文件空模块回退

解决的问题: 目录扁平化后,部分动态 import 上下文中仍引用原始文件名(如 import("./ModelMesh.js")),但文件已被重命名为哈希名(如 _9a65fcb3.js)。Webpack 在构建阶段会预先解析动态 import 上下文中的所有文件,导致 "Module not found" 错误。

工作方式:

  1. 插件初始化时在 SourceRelease/ 目录下创建 _empty_module.js(内容为 export default {};
  2. 在 resolver 的 file hook(stage: -100,先于 FileExistsPlugin 执行)中检查文件是否存在,不存在则重定向到空模块
  3. 范围限定:仅处理目标包内的 .js 文件,排除入口文件(如 clientx.js/supermap3d.js)、_shaderdecoder.js、空模块自身,以及包目录本身被当作 .js 文件解析的情况

bare import 空模块回退

解决的问题: esbuild 预打包时对解析失败的 bare import 会跳过/externalize,不阻断构建;而 Webpack 默认严格报 "Module not found" 错误并中断构建。

工作方式:

  1. 在 resolver 的 resolve hook 中拦截 bare import(如 import xxx from 'some-package'
  2. 对每个 bare import,先用 require.resolve 探测是否可解析(结果缓存,避免重复探测)
  3. 如果无法解析且包目录也不存在,则回退为空模块,构建可继续完成;如果包目录存在但 require.resolve 失败(如纯 ESM 包无 require 导出条件),则交还 Webpack 自行解析,不回退,避免误吞真实存在的依赖
  4. 范围限定:仅处理 issuer(导入发起文件)位于 @supermapgis/clientx@supermapgis/iclient3d 包内的情况(两个包均覆盖,无论当前 target 是哪个),用户项目自身源码中的导入错误不受影响,仍按 Webpack 默认行为报错
  5. 构建结束时在 finishModules 阶段汇总输出 warning(仅提示,不阻断构建),提示形式:bare import "xxx" 无法解析(被 N 个文件引用),已回退为空模块

named export 修复

解决的问题: javascript-obfuscator 混淆时可能对不同文件中的同名导出重命名不一致,导致 "export 'X' was not found" 构建错误。

工作方式:

  • 通过 module.rulesSourceRelease 目录内的 .js 文件设置 exportsPresence / importExportsPresence / reexportExportsPresence'warn'(仅警告不报错;不用 false 是因为 false 会完全跳过导出检查,可能导致有效导出无法解析)
  • 通过 ignoreWarnings 过滤来自目标包的导出警告和缺失文件警告(正则匹配 assetsDirNameSourceRelease,已转义正则特殊字符)
  • 不影响用户项目中其他 JS 文件的导出检查行为

路径大小写规范化

解决的问题: 包内部分文件用小写路径导入(如 ../core/Accessor.js),而实际目录是大写 Core/。Windows 不区分大小写所以能运行,但 Webpack 会把 core/Accessor.jsCore/Accessor.js 当作两个不同模块,产生 "multiple modules with names that only differ in casing" 警告。

工作方式: 在 resolver 的 file hook(stage: -100)中,读取文件系统上的实际目录条目,将路径规范化为实际大小写(带缓存,避免重复读取文件系统)。仅处理路径中包含 SourceRelease 的请求。

自动注入 BASE_URL

解决的问题: SDK 运行时需要通过 window.SUPERMAP3D_BASE_URL 定位静态资源(WASM、Worker、纹理等)的 URL 路径。

工作方式:processAssets(OPTIMIZE_INLINE 阶段)中,向所有 initial chunk 的 .js 文件最前面注入:

window.SUPERMAP3D_BASE_URL="/ClientX/";  // dev 模式
window.SUPERMAP3D_BASE_URL="./ClientX/"; // build 模式

路径自动适配:

| 模式 | 注入的 BASE_URL | |------|----------------| | dev | /<assetsDirName>/ | | build | ./<assetsDirName>/ | | 自定义 | options.baseUrl |

注意: window.SUPERMAP3D_BASE_URL 在 clientx 和 iclient3d 两个 target 下保持一致,不随 target 变化。

dev server 资源代理

工作方式:compiler.options.devServer.static 追加 { directory: <assetsDir>, publicPath: '/<assetsDirName>/' },webpack-dev-server 自动提供 /<assetsDirName>/ 路径下的静态资源。

重要: 插件仅在 devServer 配置对象已存在时才追加映射。如果 webpack.config.js 中完全不配置 devServer,插件无法挂载静态资源代理,项目启动后将找不到 ClientX/ 下的 WASM、Worker、纹理图片等静态资源,页面报 404。因此 devServer必须配置的(至少包含 static 字段),其余选项(hotportopen 等)按需调整。

build 资源复制

工作方式:afterEmit 钩子中(非 dev 模式时执行),将 Build/<assetsDirName>/ 下的资源目录复制到 dist/<assetsDirName>/

  • 全量模式(默认): 复制 copyFolders 中配置的所有目录
  • 过滤模式: 仅复制 keepFiles 中 glob 规则匹配的文件,减少产物体积

Widget CSS 注入

工作方式: 通过 html-webpack-pluginalterAssetTags 钩子,在 HTML <head> 中插入 <link rel="stylesheet" href="<baseUrl>Widgets/widgets.css">isAddWidgetCSS 为 true 时才注入)。


插件不处理、需要手动配置的项

以下配置插件不会自动注入,需在 webpack.config.js 中手动配置(参见快速开始中的完整示例):

| 配置项 | 推荐值 | 原因 | |--------|--------|------| | resolve.mainFields | ['module', 'browser', 'main'] | 优先使用 module 字段(指向 SourceRelease),否则 Webpack 可能解析到 main 字段 | | resolve.symlinks | false | 避免 file: 协议安装的本地 tgz 产生软链解析问题 | | module.rulesfullySpecified: false | 对 .m?js 启用 | SourceRelease 的 import 路径省略了 .js 扩展名,Webpack 5 对 ESM 要求 fully specified | | parser.javascript.amd | false | 避免 sprintfjs 的 "define cannot be used indirect" 错误 | | devServer | 至少包含 static | 插件在其上追加 SDK 资源目录映射,见上文说明 | | experiments.asyncWebAssembly | true | SDK 的 WASM 模块需要异步 WebAssembly 支持 | | CSS 相关 loader | style-loader + css-loader | 处理项目自身的 CSS 引入 |


配置示例

默认配置(推荐)

自动计算 baseUrl,自动注入 Widget CSS,开启防调试,全量拷贝静态资源:

const SuperMapLoadSDKWebpackPlugin = require('@supermapgis/webpack-plugin-loadsdk');

plugins: [
  new HtmlWebpackPlugin({ template: './index.html' }),
  new SuperMapLoadSDKWebpackPlugin(),
]

切换 target

// 集成 @supermapgis/clientx
new SuperMapLoadSDKWebpackPlugin({ target: 'clientx' })

// 集成 @supermapgis/iclient3d
new SuperMapLoadSDKWebpackPlugin({ target: 'iclient3d' })

关闭防调试(排查问题时使用)

dev 模式下需要调试 SDK 模块代码时,可关闭防调试:

new SuperMapLoadSDKWebpackPlugin({ target: 'clientx', preventDebug: false })

自定义 baseUrl

当静态资源不在默认的 ./ClientX/ 路径下时(如部署到 CDN 或自定义目录):

new SuperMapLoadSDKWebpackPlugin({ target: 'clientx', baseUrl: './ClientX/' })

关闭 Widget CSS 注入

如果项目中已手动引入 widgets.css,或不需要 Widget 样式:

new SuperMapLoadSDKWebpackPlugin({ target: 'clientx', isAddWidgetCSS: false })

静态资源过滤(减小产物体积)

默认全量拷贝会将所有静态资源目录复制到 dist/ClientX/,如果项目只需要部分资源,可开启过滤模式,仅拷贝匹配的文件:

new SuperMapLoadSDKWebpackPlugin({
  target: 'clientx',
  staticAssets: {
    filter: true,              // 开启过滤模式
    keepFiles: [               // 仅拷贝匹配以下 glob 规则的文件
      'Assets/**/*',           // 纹理、模型等资源
      'SkyAtmosphereSystem/**/*', // 天空大气资源
      'ThirdParty/**/*',       // 第三方库(WASM 等)
      'Widgets/**/*',          // Widget CSS
      'Workers/**/*',          // Worker 脚本
    ]
  }
})

常用 glob 模式:

| 模式 | 说明 | |------|------| | Assets/**/* | Assets 目录下的所有文件(含子目录) | | Workers/*.js | Workers 根目录下的所有 .js 文件 | | Workers/**/*.js | Workers 及其子目录下的所有 .js 文件 | | ThirdParty/**/*.wasm | ThirdParty 目录下所有 WASM 文件 | | Widgets/**/*.css | 所有 Widget CSS 文件 |


用户代码写法

插件配置好后,用户代码非常简洁,无需任何手动设置:

全量导入(默认):

import * as ClientX from '@supermapgis/clientx';

const viewer = new ClientX.Viewer("Container", {});
window.viewer = viewer;

按需导入(利用 tree-shaking 减小产物体积):

import { Viewer } from '@supermapgis/clientx';
const viewer = new Viewer("Container", {});
import { Cartesian3, Cartographic, Math } from '@supermapgis/clientx';
const c3 = Cartesian3.fromDegrees(116.45, 39.91, 5);

缓存清理

当依赖更新后页面未生效,可清除构建缓存:

rmdir /s /q node_modules\.cache
npm run dev

许可证

Apache-2.0