From 742dc44b139162169d64646a1892119f22de9305 Mon Sep 17 00:00:00 2001 From: Martin Schuhfuss Date: Fri, 24 Oct 2025 14:37:07 +0200 Subject: [PATCH 1/2] fix: replace `__DEV__` with `process.env.NODE_ENV` for environment checks Refactor the build process to remove the custom `__DEV__` global declaration and replace it with a more standard `process.env.NODE_ENV !== 'production'` pattern. Adjusted rollup configuration accordingly. --- rollup.config.js | 10 +--------- src/index.ts | 5 +++-- src/messages.ts | 5 +++-- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index 9fd0f7b0..4f6779d6 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -67,15 +67,7 @@ export default [ // ESM build { input: "src/index.ts", - plugins: [ - ...basePlugins, - replace({ - preventAssignment: true, - values: { - __DEV__: 'process.env.NODE_ENV !== "production"', - }, - }), - ], + plugins: [...basePlugins], output: { file: "dist/index.js", format: "esm", diff --git a/src/index.ts b/src/index.ts index 835172b0..15fa59e8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -59,8 +59,9 @@ interface APILibraryMap { type APILibraryName = keyof APILibraryMap; -// The __DEV__ global variable is set by rollup during the build process. -declare const __DEV__: boolean; +// Development mode check - bundlers will replace process.env.NODE_ENV at build time +declare const process: { env: { NODE_ENV?: string } }; +const __DEV__ = process.env.NODE_ENV !== 'production'; let setOptionsWasCalled_ = false; diff --git a/src/messages.ts b/src/messages.ts index bc1b15ce..1699ce46 100644 --- a/src/messages.ts +++ b/src/messages.ts @@ -44,8 +44,9 @@ export const MSG_SCRIPT_ELEMENT_EXISTS = "problems using the API. Make sure to remove the script " + "loading the API."; -// The __DEV__ global variable is set by rollup during the build process. -declare const __DEV__: boolean; +// Development mode check - bundlers will replace process.env.NODE_ENV at build time +declare const process: { env: { NODE_ENV?: string } }; +const __DEV__ = process.env.NODE_ENV !== 'production'; export const logError = (message: string) => { console.error(`[@googlemaps/js-api-loader] ${message}`); From bec05d5a0ce43d95a2eca4518eae2ff0e0c7d81f Mon Sep 17 00:00:00 2001 From: Martin Schuhfuss Date: Fri, 24 Oct 2025 14:50:22 +0200 Subject: [PATCH 2/2] test: add bundler integration tests for vite, webpack, and rollup Introduce bundler-specific test setups to ensure `@googlemaps/js-api-loader` works seamlessly with Vite, Webpack, and Rollup. Includes build scripts, configurations, and validation for production and development modes. --- eslint.config.js | 2 +- package.json | 4 +- test-bundlers/.gitignore | 10 ++ test-bundlers/README.md | 69 +++++++++ test-bundlers/rollup-test/package.json | 19 +++ .../rollup-test/rollup.config.dev.js | 20 +++ test-bundlers/rollup-test/rollup.config.js | 21 +++ test-bundlers/rollup-test/src/index.js | 33 +++++ test-bundlers/test-all.sh | 138 ++++++++++++++++++ test-bundlers/vite-test/index.html | 24 +++ test-bundlers/vite-test/package.json | 16 ++ test-bundlers/vite-test/src/main.js | 33 +++++ test-bundlers/vite-test/vite.config.js | 9 ++ test-bundlers/webpack-test/package.json | 16 ++ test-bundlers/webpack-test/src/index.js | 33 +++++ test-bundlers/webpack-test/webpack.config.js | 16 ++ 16 files changed, 461 insertions(+), 2 deletions(-) create mode 100644 test-bundlers/.gitignore create mode 100644 test-bundlers/README.md create mode 100644 test-bundlers/rollup-test/package.json create mode 100644 test-bundlers/rollup-test/rollup.config.dev.js create mode 100644 test-bundlers/rollup-test/rollup.config.js create mode 100644 test-bundlers/rollup-test/src/index.js create mode 100755 test-bundlers/test-all.sh create mode 100644 test-bundlers/vite-test/index.html create mode 100644 test-bundlers/vite-test/package.json create mode 100644 test-bundlers/vite-test/src/main.js create mode 100644 test-bundlers/vite-test/vite.config.js create mode 100644 test-bundlers/webpack-test/package.json create mode 100644 test-bundlers/webpack-test/src/index.js create mode 100644 test-bundlers/webpack-test/webpack.config.js diff --git a/eslint.config.js b/eslint.config.js index 97c3ac57..68bfc6e9 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -6,7 +6,7 @@ import { defineConfig } from "eslint/config"; export default defineConfig( { - ignores: ["dist/", "node_modules/", "src/bootstrap.js"], + ignores: ["**/dist/", "**/node_modules/", "src/bootstrap.js"], }, { languageOptions: { diff --git a/package.json b/package.json index e8ea0edf..bc276816 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,9 @@ "scripts": { "prepack": "npm run build", "lint": "eslint .", - "test": "NODE_OPTIONS='--experimental-vm-modules --disable-warning=ExperimentalWarning' jest ./src", + "test": "npm run lint && npm run test:unit && npm run test:bundlers", + "test:unit": "NODE_OPTIONS='--experimental-vm-modules --disable-warning=ExperimentalWarning' jest ./src", + "test:bundlers": "cd test-bundlers && ./test-all.sh", "build": "rm -rf ./dist && rollup -c", "format": "eslint . --fix" }, diff --git a/test-bundlers/.gitignore b/test-bundlers/.gitignore new file mode 100644 index 00000000..551a681c --- /dev/null +++ b/test-bundlers/.gitignore @@ -0,0 +1,10 @@ +# Dependencies +node_modules/ +package-lock.json + +# Build outputs +*/dist/ +*/build.log + +# Tarball +*.tgz diff --git a/test-bundlers/README.md b/test-bundlers/README.md new file mode 100644 index 00000000..aec6cbc7 --- /dev/null +++ b/test-bundlers/README.md @@ -0,0 +1,69 @@ +# Bundler Integration Tests + +This directory contains integration tests to verify that +`@googlemaps/js-api-loader` works correctly with popular JavaScript bundlers +without requiring any configuration from consumers. + +The @googlemaps/js-api-loader library has a development-mode (based on +`process.env.NODE_ENV` checks) that toggle detailed warning messages during +development. + +The tests in this directory ensure that some of the most popular bundlers +correctly handle the development mode in a default configuration. + +1. **Vite** - Correctly replaces `process.env.NODE_ENV` via its built-in + `define` config +2. **Webpack** - Correctly replaces it via DefinePlugin (default behavior) +3. **Rollup** - Works with standard `@rollup/plugin-replace` configuration + +The tests verify both modes: + +- **Production mode**: `process.env.NODE_ENV` is replaced, dev warnings are + removed +- **Development mode**: `process.env.NODE_ENV` is replaced with `"development"`, + dev warnings are preserved + +## Running Tests + +```bash +./test-all.sh +``` + +### Individual bundler: + +```bash +cd vite-test +npm install +npm install $(npm pack --silent ../../) +npm run build +``` + +## What Each Test Does + +### Vite (`vite-test/`) + +- Uses Vite's zero-config setup +- Relies on Vite's automatic `process.env.NODE_ENV` replacement +- development mode is approximated by disabling minification and building with + `NODE_ENV='development' vite build --mode development` + +### Webpack (`webpack-test/`) + +- Uses Webpack 5 with minimal config +- Relies on DefinePlugin (enabled by default in production mode) + +### Rollup (`rollup-test/`) + +- Uses standard Rollup with `@rollup/plugin-replace` +- Represents how users typically configure Rollup + +## Expected Output + +All tests should pass with: + +``` +✓ All bundler tests passed! +``` + +If any test fails, it means the library is shipping code that won't work +correctly in that bundler without additional user configuration. diff --git a/test-bundlers/rollup-test/package.json b/test-bundlers/rollup-test/package.json new file mode 100644 index 00000000..cfe55777 --- /dev/null +++ b/test-bundlers/rollup-test/package.json @@ -0,0 +1,19 @@ +{ + "name": "rollup-test", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "rollup -c", + "build:dev": "rollup -c rollup.config.dev.js" + }, + "devDependencies": { + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "rollup": "^4.6.1" + }, + "dependencies": { + "@googlemaps/js-api-loader": "file:../../googlemaps-js-api-loader-2.0.1.tgz" + } +} diff --git a/test-bundlers/rollup-test/rollup.config.dev.js b/test-bundlers/rollup-test/rollup.config.dev.js new file mode 100644 index 00000000..b821f73a --- /dev/null +++ b/test-bundlers/rollup-test/rollup.config.dev.js @@ -0,0 +1,20 @@ +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import replace from "@rollup/plugin-replace"; + +export default { + input: "src/index.js", + output: { + file: "dist/bundle.js", + format: "esm", + }, + plugins: [ + nodeResolve(), + replace({ + preventAssignment: true, + values: { + "process.env.NODE_ENV": JSON.stringify("development"), + }, + }), + // Note: No minification in dev mode + ], +}; diff --git a/test-bundlers/rollup-test/rollup.config.js b/test-bundlers/rollup-test/rollup.config.js new file mode 100644 index 00000000..77c03a1f --- /dev/null +++ b/test-bundlers/rollup-test/rollup.config.js @@ -0,0 +1,21 @@ +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import replace from "@rollup/plugin-replace"; +import terser from "@rollup/plugin-terser"; + +export default { + input: "src/index.js", + output: { + file: "dist/bundle.js", + format: "esm", + }, + plugins: [ + nodeResolve(), + replace({ + preventAssignment: true, + values: { + "process.env.NODE_ENV": JSON.stringify("production"), + }, + }), + terser(), + ], +}; diff --git a/test-bundlers/rollup-test/src/index.js b/test-bundlers/rollup-test/src/index.js new file mode 100644 index 00000000..66638128 --- /dev/null +++ b/test-bundlers/rollup-test/src/index.js @@ -0,0 +1,33 @@ +import { importLibrary, setOptions } from "@googlemaps/js-api-loader"; + +// Configure the Google Maps API +setOptions({ + apiKey: "YOUR_API_KEY", + version: "weekly", +}); + +// Initialize the map +async function initMap() { + const { Map } = await importLibrary("maps"); + + return new Map(document.getElementById("map"), { + center: { lat: 37.7749, lng: -122.4194 }, + zoom: 12, + }); +} + +// Load markers +async function addMarkers(map) { + const { AdvancedMarkerElement } = await importLibrary("marker"); + + const marker = new AdvancedMarkerElement({ + position: { lat: 37.7749, lng: -122.4194 }, + title: "San Francisco", + }); + marker.map = map; +} + +// Start the application +initMap() + .then((map) => addMarkers(map)) + .catch(console.error); diff --git a/test-bundlers/test-all.sh b/test-bundlers/test-all.sh new file mode 100755 index 00000000..da453970 --- /dev/null +++ b/test-bundlers/test-all.sh @@ -0,0 +1,138 @@ +#!/bin/bash + +# Test bundler compatibility for @googlemaps/js-api-loader +# This script tests that the library works with various popular bundlers +# without requiring any configuration from the user. + +set -e # Exit on any error + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" + +echo "======================================" +echo "Testing Bundler Compatibility" +echo "======================================" +echo "" + +# Colors for output +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Pack the library +echo "📦 Packing library..." +cd "$ROOT_DIR" +TARBALL=$(npm pack --silent 2> /dev/null) +echo " created: $TARBALL" +echo "" + +for bundler in vite webpack rollup ; do + dir="$SCRIPT_DIR/${bundler}-test" + + ( + cd $dir + # Install dependencies + echo " Installing dependencies for $bundler..." + npm install --silent + npm install --silent "../../$TARBALL" + ) +done + +echo "" + +# Function to test a bundler in production mode +test_bundler_prod() { + local bundler=$1 + local dir="$SCRIPT_DIR/${bundler}-test" + + cd "$dir" + + echo "Testing $bundler (production)..." + + # Run production build + echo " Building (production)..." + if npm run build > build.log 2>&1; then + # Check for process.env.NODE_ENV references in actual code (not in strings/comments) + # We pipe find to xargs to grep through all bundles at once. + # The if condition checks the exit code of grep. + if find dist -name "*.js" -type f -print0 | xargs -0 grep -qE "process\.env\.NODE_ENV|process\.env\\["; then + echo -e " ${RED}✗ NUM_FAILED${NC} - Found process.env.NODE_ENV in bundle code" + return 1 + fi + + # Verify that importLibrary is still present (not tree-shaken) + if ! find dist -name "*.js" -type f -exec grep -q "importLibrary" {} \;; then + echo -e " ${RED}✗ NUM_FAILED${NC} - importLibrary was incorrectly tree-shaken" + return 1 + fi + + echo -e " ${GREEN}✓ PASSED${NC} - process.env replaced, bundle optimized" + return 0 + else + echo -e " ${RED}✗ NUM_FAILED${NC} - Build error" + echo "~~~~ build log:" + cat build.log + echo "~~~~" + + return 1 + fi +} + +# Function to test a bundler in development mode +test_bundler_dev() { + local bundler=$1 + local dir="$SCRIPT_DIR/${bundler}-test" + + cd "$dir" + + echo "Testing $bundler (development)..." + + # Run development build + echo " Building (development)..." + rm -rf dist + if npm run build:dev > build-dev.log 2>&1; then + # Check that dev warning code is present in the bundle + # We look for the actual console.warn message, not just the function definition. + if find dist -name "*.js" -type f -print0 | xargs -0 grep -qE "console\.warn.*@googlemaps/js-api-loader"; then + echo -e " ${GREEN}✓ PASSED${NC} - dev warnings preserved" + return 0 + else + echo -e " ${RED}✗ NUM_FAILED${NC} - dev warning code not found (dead code eliminated incorrectly)" + cat build-dev.log + return 1 + fi + else + echo -e " ${RED}✗ NUM_FAILED${NC} - Build error" + cat build-dev.log + return 1 + fi +} + +NUM_FAILED=0 + +# Production mode tests +echo "========== PRODUCTION MODE ==========" + +for bundler in vite webpack rollup ; do + echo "" + test_bundler_prod $bundler || NUM_FAILED=$((NUM_FAILED + 1)) +done +echo "" + +# Development mode tests +echo "========== DEVELOPMENT MODE ==========" +for bundler in vite webpack rollup ; do + echo "" + test_bundler_dev $bundler || NUM_FAILED=$((NUM_FAILED + 1)) +done +echo "" + +# Summary +echo "======================================" +if [ $NUM_FAILED -eq 0 ]; then + echo -e "${GREEN}✓ All bundler tests passed!${NC}" + exit 0 +else + echo -e "${RED}✗ $NUM_FAILED bundler test(s) failed${NC}" + exit 1 +fi diff --git a/test-bundlers/vite-test/index.html b/test-bundlers/vite-test/index.html new file mode 100644 index 00000000..33d605b3 --- /dev/null +++ b/test-bundlers/vite-test/index.html @@ -0,0 +1,24 @@ + + + + + + Vite Test - Google Maps + + + +
+ + + diff --git a/test-bundlers/vite-test/package.json b/test-bundlers/vite-test/package.json new file mode 100644 index 00000000..3794bfe3 --- /dev/null +++ b/test-bundlers/vite-test/package.json @@ -0,0 +1,16 @@ +{ + "name": "vite-test", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "vite build", + "build:dev": "NODE_ENV=development vite build --mode development" + }, + "devDependencies": { + "vite": "^5.0.0" + }, + "dependencies": { + "@googlemaps/js-api-loader": "file:../../googlemaps-js-api-loader-2.0.1.tgz" + } +} diff --git a/test-bundlers/vite-test/src/main.js b/test-bundlers/vite-test/src/main.js new file mode 100644 index 00000000..66638128 --- /dev/null +++ b/test-bundlers/vite-test/src/main.js @@ -0,0 +1,33 @@ +import { importLibrary, setOptions } from "@googlemaps/js-api-loader"; + +// Configure the Google Maps API +setOptions({ + apiKey: "YOUR_API_KEY", + version: "weekly", +}); + +// Initialize the map +async function initMap() { + const { Map } = await importLibrary("maps"); + + return new Map(document.getElementById("map"), { + center: { lat: 37.7749, lng: -122.4194 }, + zoom: 12, + }); +} + +// Load markers +async function addMarkers(map) { + const { AdvancedMarkerElement } = await importLibrary("marker"); + + const marker = new AdvancedMarkerElement({ + position: { lat: 37.7749, lng: -122.4194 }, + title: "San Francisco", + }); + marker.map = map; +} + +// Start the application +initMap() + .then((map) => addMarkers(map)) + .catch(console.error); diff --git a/test-bundlers/vite-test/vite.config.js b/test-bundlers/vite-test/vite.config.js new file mode 100644 index 00000000..f3f4f810 --- /dev/null +++ b/test-bundlers/vite-test/vite.config.js @@ -0,0 +1,9 @@ +import { defineConfig } from 'vite'; + +export default defineConfig(({ mode }) => ({ + build: { + // The 'vite build' command minifies by default. We need to explicitly + // disable it for development mode to keep the debug messages. + minify: mode === 'production', + }, +})); diff --git a/test-bundlers/webpack-test/package.json b/test-bundlers/webpack-test/package.json new file mode 100644 index 00000000..c3ccc2a2 --- /dev/null +++ b/test-bundlers/webpack-test/package.json @@ -0,0 +1,16 @@ +{ + "name": "webpack-test", + "private": true, + "version": "0.0.0", + "scripts": { + "build": "webpack --mode=production", + "build:dev": "webpack --mode=development" + }, + "devDependencies": { + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" + }, + "dependencies": { + "@googlemaps/js-api-loader": "file:../../googlemaps-js-api-loader-2.0.1.tgz" + } +} diff --git a/test-bundlers/webpack-test/src/index.js b/test-bundlers/webpack-test/src/index.js new file mode 100644 index 00000000..66638128 --- /dev/null +++ b/test-bundlers/webpack-test/src/index.js @@ -0,0 +1,33 @@ +import { importLibrary, setOptions } from "@googlemaps/js-api-loader"; + +// Configure the Google Maps API +setOptions({ + apiKey: "YOUR_API_KEY", + version: "weekly", +}); + +// Initialize the map +async function initMap() { + const { Map } = await importLibrary("maps"); + + return new Map(document.getElementById("map"), { + center: { lat: 37.7749, lng: -122.4194 }, + zoom: 12, + }); +} + +// Load markers +async function addMarkers(map) { + const { AdvancedMarkerElement } = await importLibrary("marker"); + + const marker = new AdvancedMarkerElement({ + position: { lat: 37.7749, lng: -122.4194 }, + title: "San Francisco", + }); + marker.map = map; +} + +// Start the application +initMap() + .then((map) => addMarkers(map)) + .catch(console.error); diff --git a/test-bundlers/webpack-test/webpack.config.js b/test-bundlers/webpack-test/webpack.config.js new file mode 100644 index 00000000..5f98ce47 --- /dev/null +++ b/test-bundlers/webpack-test/webpack.config.js @@ -0,0 +1,16 @@ +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export default { + entry: './src/index.js', + output: { + filename: 'bundle.js', + path: path.resolve(__dirname, 'dist'), + }, + mode: 'production', + optimization: { + minimize: true + } +};