0Pricing
React Native Academy · บทเรียน

การเผยแพร่ปลั๊กอินการกำหนดค่าเป็นแพ็กเกจ npm

จัดแพ็กเกจปลั๊กอินการกำหนดค่าเป็นโมดูล npm เพิ่มจุดเริ่มต้น app.plugin.js เผยแพร่ไปยัง npm และติดตั้งในโปรเจกต์ Expo อื่นเพื่อตรวจสอบว่าปลั๊กอินทำงานถูกต้อง

การเผยแพร่ปลั๊กอินการกำหนดค่าเป็นแพ็กเกจ npm เป็นบทเรียน React Native Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน React Native Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ

Why Package a Config Plugin

If you use the same config plugin across multiple Expo projects, or want to share it with the React Native community, packaging it as an npm module makes distribution easy. Consumers install it with npm install and reference it by package name in app.json. Expo automatically discovers the app.plugin.js file at the package root without any extra configuration from the consumer.

Structuring the npm Package

A config plugin npm package has a minimal structure: a package.json, an app.plugin.js entry point at the package root (this is the file Expo looks for), and optionally a src/ folder for TypeScript source that compiles to the plugin file. The app.plugin.js filename is the Expo convention — do not name it differently or Expo cannot auto-discover it.

# Package structure
expo-plugin-my-sdk/
  app.plugin.js         <- Expo auto-discovers this
  index.js              <- optional JS API exports
  package.json
  README.md

# Or with TypeScript build:
expo-plugin-my-sdk/
  src/
    withMyPlugin.ts
    index.ts
  build/
    withMyPlugin.js     <- compiled output
  app.plugin.js         <- re-exports from build/
  package.json

The app.plugin.js Entry Point

The app.plugin.js file must export a single function as its default export using module.exports (CommonJS). This function is the config plugin itself — it takes config and optional options, applies modifications, and returns the modified config. If your package has a TypeScript build step, app.plugin.js simply re-exports from the compiled build/ directory.

// app.plugin.js (root of the npm package)
// Simple single-file plugin:
const { withInfoPlist } = require('@expo/config-plugins');

/** @type {import('@expo/config-plugins').ConfigPlugin<{ apiKey?: string }>} */
module.exports = function withMySDK(config, options = {}) {
  if (!options.apiKey) {
    throw new Error('[expo-plugin-my-sdk] apiKey option is required.');
  }

  return withInfoPlist(config, (iosConfig) => {
    iosConfig.modResults['MySDKApiKey'] = options.apiKey;
    return iosConfig;
  });
};

Configuring package.json

The package.json for a config plugin package needs the standard fields plus a few Expo-specific conventions. Set main to your compiled JS entry (not app.plugin.js — that's separate). List @expo/config-plugins in peerDependencies (not regular dependencies) so consumers use their own installed version and avoid duplicate installs. Prefix the package name with expo- or use a scoped name like @yourorg/expo-plugin-name.

{
  'name': 'expo-plugin-my-sdk',
  'version': '1.0.0',
  'description': 'Expo config plugin for MySDK',
  'main': 'build/index.js',
  'files': ['build', 'app.plugin.js'],
  'scripts': {
    'build': 'tsc',
    'prepare': 'npm run build'
  },
  'peerDependencies': {
    '@expo/config-plugins': '>=7.0.0',
    'expo': '>=50.0.0'
  },
  'devDependencies': {
    '@expo/config-plugins': '^7.0.0',
    'typescript': '^5.0.0'
  }
}

Writing the Plugin in TypeScript

@expo/config-plugins exports TypeScript types, making it easy to type your plugin properly. Use the ConfigPlugin generic type with your options interface. TypeScript catches type errors (like passing an invalid manifest key) at compile time rather than at the consumer's prebuild time. Generate declaration files (.d.ts) so consumers get IntelliSense when passing options.

// src/withMySDK.ts
import { ConfigPlugin, withInfoPlist, withAndroidManifest } from '@expo/config-plugins';

interface MySDKOptions {
  apiKey: string;
  enableAnalytics?: boolean;
}

const withMySDK: ConfigPlugin<MySDKOptions> = (config, options) => {
  if (!options.apiKey) {
    throw new Error('[expo-plugin-my-sdk] apiKey is required');
  }

  config = withInfoPlist(config, (c) => {
    c.modResults['MySDKApiKey'] = options.apiKey;
    c.modResults['MySDKAnalytics'] = options.enableAnalytics ?? true;
    return c;
  });

  return config;
};

export default withMySDK;

Re-exporting from app.plugin.js

When using TypeScript, your source code is compiled to build/ but Expo looks for app.plugin.js at the root. Create a minimal app.plugin.js that requires the compiled output. This separation keeps TypeScript source clean while providing the correct entry point that Expo's module resolution expects. The file is typically just one or two lines.

// app.plugin.js (root)
// Re-export the compiled TypeScript plugin
module.exports = require('./build/withMySDK').default;

// Or with named export:
// const { withMySDK } = require('./build/index');
// module.exports = withMySDK;

Installing and Using the Published Plugin

Once published to npm, consumers install the package and add it to app.json plugins. Expo resolves the package by name, finds app.plugin.js in the node_modules folder, and runs it during prebuild. The consumer passes options as the second element of the plugin array tuple. This is exactly the same developer experience as Expo's own first-party plugins.

# Install the plugin
npm install expo-plugin-my-sdk

# app.json
{
  'expo': {
    'plugins': [
      [
        'expo-plugin-my-sdk',
        {
          'apiKey': 'sk-live-abc123',
          'enableAnalytics': true
        }
      ]
    ]
  }
}

Testing Before Publishing

Before publishing to npm, test your plugin locally using npm link or a relative file: path in the test app's package.json. This lets you iterate quickly without publishing. After local testing, use npm pack to create a tarball and inspect its contents to verify the correct files are included. Only publish once you confirm the plugin works end-to-end.

# Method 1: npm link (symlink)
cd expo-plugin-my-sdk
npm link
cd ../my-test-app
npm link expo-plugin-my-sdk
npx expo prebuild --clean

# Method 2: file path in package.json
{
  'dependencies': {
    'expo-plugin-my-sdk': 'file:../expo-plugin-my-sdk'
  }
}

# Inspect pack output before publishing
npm pack --dry-run

Publishing to npm

Publish your plugin with npm publish. Make sure the files field in package.json includes app.plugin.js and build/ but excludes src/ (TypeScript source consumers do not need). Use semantic versioning: bump the patch version for bug fixes, minor for new options, and major when you change the config in a breaking way (e.g., rename an option).

# Login to npm
npm login

# Verify what will be published
npm pack --dry-run
# Should include:
#   app.plugin.js
#   build/withMySDK.js
#   build/withMySDK.d.ts
#   package.json
#   README.md

# Publish
npm publish

# For scoped packages (public)
npm publish --access public

Writing a Good README

A config plugin README should include: the installation command, the exact app.json snippet showing all available options, a table documenting each option with its type, default, and description, and the list of native changes the plugin makes (which permissions it adds, what Info.plist keys it sets). Developers need to understand what the plugin changes before trusting it with their native project.

## Installation
npm install expo-plugin-my-sdk

## Setup (app.json)
[
  'expo-plugin-my-sdk',
  {
    'apiKey': 'your-api-key',
    'enableAnalytics': true
  }
]

## Options
| Option            | Type    | Required | Default | Description          |
|-------------------|---------|----------|---------|----------------------|
| apiKey            | string  | yes      | -       | Your MySDK API key   |
| enableAnalytics   | boolean | no       | true    | Enable analytics     |

## Native Changes
- iOS: Adds `MySDKApiKey` to Info.plist
- Android: Adds `<meta-data android:name="com.mysdk.API_KEY" />` to AndroidManifest

Versioning and Breaking Changes

Config plugin consumers run expo prebuild to apply your plugin — they do not call your code directly at runtime. Breaking changes include: renaming options, removing options, changing the type of an option, or producing different native output that removes a previously added entry. Always document breaking changes in a CHANGELOG.md and increment the major version so consumers can pin to a safe version.

// CHANGELOG.md example

## [2.0.0] - Breaking Changes
- BREAKING: Renamed `apiKey` option to `publishableKey` to match SDK terminology
- BREAKING: Removed `enableAnalytics` option (now always enabled)
- Added `merchantId` option for Apple Pay support

## [1.2.0]
- Added `enableAnalytics` option

## [1.1.0]
- Added Android support (previously iOS only)

## [1.0.0]
- Initial release: iOS Info.plist configuration

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: how to structure an npm package for a config plugin with app.plugin.js at the root, how to write the plugin in TypeScript and re-export from app.plugin.js, and how to test locally with npm link before publishing. You also saw how to configure package.json with the correct peerDependencies and files fields. Next up we cover the iOS App Store submission process.

คำถามที่พบบ่อย

บทเรียน “การเผยแพร่ปลั๊กอินการกำหนดค่าเป็นแพ็กเกจ npm” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเผยแพร่ปลั๊กอินการกำหนดค่าเป็นแพ็กเกจ npm” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส React Native Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเผยแพร่ปลั๊กอินการกำหนดค่าเป็นแพ็กเกจ npm”

จัดแพ็กเกจปลั๊กอินการกำหนดค่าเป็นโมดูล npm เพิ่มจุดเริ่มต้น app.plugin.js เผยแพร่ไปยัง npm และติดตั้งในโปรเจกต์ Expo อื่นเพื่อตรวจสอบว่าปลั๊กอินทำงานถูกต้อง คุณปฏิบัติ React Native Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน React Native Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน React Native Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การเผยแพร่ปลั๊กอินการกำหนดค่าเป็นแพ็กเกจ npm” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน React Native Academy นี้ได้ไหม

ได้ บทเรียน React Native Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ปลั๊กอินการกำหนดค่าคืออะไรและควรใช้เมื่อใด
  2. การเขียนปลั๊กอินการกำหนดค่าแรก
  3. การแก้ไข AndroidManifest และ Info.plist
  4. การเผยแพร่ปลั๊กอินการกำหนดค่าเป็นแพ็กเกจ npm
← กลับไปที่ React Native Academy