패키지 개발

업데이트됨

번역일: 2026년 7월 17일

이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.

원문 수정
2026년 7월 17일
번역 갱신
2026년 7월 17일

패키지 개발

소개

패키지는 Laravel에 기능을 추가하는 가장 기본적인 방법입니다. 날짜 처리를 편리하게 해주는 Carbon부터, Eloquent 모델에 파일을 연결할 수 있게 해주는 Spatie의 Laravel Media Library까지, 다양한 패키지가 존재합니다.

패키지는 크게 두 가지 종류로 나뉩니다. 독립형(stand-alone) 패키지는 어떤 PHP 프레임워크와도 함께 사용할 수 있습니다. Carbon과 Pest가 대표적인 예입니다. 이런 패키지는 composer.json에 추가하기만 하면 Laravel에서도 바로 사용할 수 있습니다.

반면, Laravel 전용 패키지는 라우트, 컨트롤러, 뷰, 설정 파일 등 Laravel 애플리케이션에 특화된 기능을 제공합니다. 이 문서는 주로 이러한 Laravel 전용 패키지 개발에 대해 다룹니다.

패키지 생성

새 Laravel 패키지를 시작하는 가장 쉬운 방법은 공식 Laravel 패키지 스켈레톤을 사용하는 것입니다. 이 스켈레톤에는 서비스 프로바이더, Pest 기반 테스트, Larastan을 이용한 정적 분석, Pint를 이용한 코드 포맷팅, 그리고 엔드-투-엔드 패키지 개발을 위한 워크벤치 애플리케이션이 모두 포함되어 있습니다. Laravel 인스톨러 CLIpackage 명령어로 새 패키지를 만들 수 있습니다:

laravel package my-package

명령어를 실행하면 대화형 설정 스크립트가 시작됩니다. 네임스페이스, 서비스 프로바이더를 설정하고, 설정 파일, 라우트, 뷰, 번역, 마이그레이션, 에셋, 명령어, Facade 등 필요한 기능만 선택적으로 구성할 수 있습니다.

Facade에 관한 참고 사항

일반적인 Laravel 애플리케이션을 개발할 때는 Contract와 Facade 중 어느 것을 사용해도 테스트 용이성에서 큰 차이가 없습니다. 그러나 패키지를 개발할 때는 상황이 다릅니다. 패키지 환경에서는 Laravel의 테스트 헬퍼 전체에 접근하기 어려울 수 있습니다.

패키지 테스트를 일반 Laravel 애플리케이션에 설치된 것처럼 작성하고 싶다면 Orchestral Testbench 패키지를 사용하는 것을 권장합니다.

패키지 자동 감지

Laravel 애플리케이션의 bootstrap/providers.php 파일에는 로드할 서비스 프로바이더 목록이 담겨 있습니다. 그런데 패키지 사용자가 직접 이 파일에 서비스 프로바이더를 추가하게 하는 대신, 패키지의 composer.json 파일 extra 섹션에 서비스 프로바이더를 정의하면 Laravel이 자동으로 로드합니다. 서비스 프로바이더 외에 Facade도 함께 등록할 수 있습니다:

"extra": { "laravel": { "providers": [ "Barryvdh\\Debugbar\\ServiceProvider" ], "aliases": { "Debugbar": "Barryvdh\\Debugbar\\Facade" } } },

자동 감지가 설정되면, 패키지가 설치될 때 Laravel이 서비스 프로바이더와 Facade를 자동으로 등록합니다. 사용자 입장에서는 별도 설정 없이 바로 패키지를 사용할 수 있어 편리합니다.

패키지 자동 감지 비활성화

패키지를 사용하는 입장에서 특정 패키지의 자동 감지를 비활성화하고 싶다면, 애플리케이션의 composer.json 파일 extra 섹션에 해당 패키지를 명시하면 됩니다:

"extra": { "laravel": { "dont-discover": [ "barryvdh/laravel-debugbar" ] } },

* 문자를 사용하면 모든 패키지의 자동 감지를 한 번에 비활성화할 수 있습니다:

"extra": { "laravel": { "dont-discover": [ "*" ] } },

서비스 프로바이더

서비스 프로바이더는 패키지와 Laravel을 연결하는 핵심 지점입니다. 서비스 프로바이더는 Laravel의 서비스 컨테이너에 필요한 것들을 바인딩하고, 뷰·설정·언어 파일 등 패키지 리소스의 위치를 Laravel에 알려주는 역할을 합니다.

서비스 프로바이더는 Illuminate\Support\ServiceProvider 클래스를 상속하며 registerboot 두 메서드를 포함합니다. 기반 클래스인 ServiceProviderilluminate/support Composer 패키지에 포함되어 있으므로, 이를 패키지의 의존성에 추가해야 합니다. 서비스 프로바이더의 구조와 역할에 대한 자세한 내용은 서비스 프로바이더 문서를 참고하세요.

리소스

설정

일반적으로 패키지의 설정 파일을 애플리케이션의 config 디렉토리에 퍼블리싱할 수 있게 해야 합니다. 그래야 사용자가 기본 설정 값을 쉽게 재정의할 수 있습니다. 서비스 프로바이더의 boot 메서드에서 publishes 메서드를 호출하면 됩니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { $this->publishes([ __DIR__.'/../config/courier.php' => config_path('courier.php'), ]); }

이제 사용자가 vendor:publish 명령어를 실행하면 설정 파일이 지정된 위치로 복사됩니다. 퍼블리싱된 후에는 일반 설정 파일처럼 값에 접근할 수 있습니다:

$value = config('courier.option');

WARNING

설정 파일에 클로저를 정의하지 마세요. 사용자가 config:cache Artisan 명령어를 실행할 때 클로저는 올바르게 직렬화되지 않습니다.

패키지 기본 설정 병합

패키지 자체의 기본 설정 파일과 사용자가 퍼블리싱한 설정 파일을 병합할 수도 있습니다. 이렇게 하면 사용자는 변경하고 싶은 항목만 퍼블리싱된 파일에 정의하면 됩니다. 서비스 프로바이더의 register 메서드에서 mergeConfigFrom 메서드를 사용하세요.

mergeConfigFrom의 첫 번째 인자는 패키지 설정 파일 경로, 두 번째 인자는 애플리케이션 설정 파일 이름입니다:

/** * 패키지 서비스를 등록합니다. */ public function register(): void { $this->mergeConfigFrom( __DIR__.'/../config/courier.php', 'courier' ); }

WARNING

이 메서드는 설정 배열의 1단계(최상위 레벨)만 병합합니다. 다차원 배열의 일부만 정의된 경우, 누락된 하위 옵션은 병합되지 않으니 주의하세요.

라우트

패키지에 라우트 파일이 포함되어 있다면 loadRoutesFrom 메서드로 로드할 수 있습니다. 이 메서드는 애플리케이션의 라우트가 캐시되어 있는지 자동으로 확인하며, 이미 캐시된 경우에는 라우트 파일을 다시 로드하지 않습니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { $this->loadRoutesFrom(__DIR__.'/../routes/web.php'); }

마이그레이션

패키지에 데이터베이스 마이그레이션이 포함된 경우, publishesMigrations 메서드를 사용해 해당 디렉토리나 파일이 마이그레이션을 포함하고 있음을 Laravel에 알릴 수 있습니다. 마이그레이션이 퍼블리싱될 때, 파일명의 타임스탬프는 현재 날짜와 시간으로 자동 업데이트됩니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { $this->publishesMigrations([ __DIR__.'/../database/migrations' => database_path('migrations'), ]); }

언어 파일

패키지에 언어 파일이 포함된 경우, loadTranslationsFrom 메서드로 로드 위치를 Laravel에 알려줄 수 있습니다. 예를 들어 패키지 이름이 courier라면 서비스 프로바이더의 boot 메서드에 아래와 같이 추가합니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier'); }

패키지 번역 문자열은 패키지::파일.키 형식으로 참조합니다. 예를 들어 courier 패키지의 messages 파일에서 welcome 항목을 불러오려면 다음과 같이 씁니다:

echo trans('courier::messages.welcome');

JSON 형식의 번역 파일을 사용한다면 loadJsonTranslationsFrom 메서드를 사용하세요. JSON 번역 파일이 위치한 디렉토리 경로를 인자로 전달합니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { $this->loadJsonTranslationsFrom(__DIR__.'/../lang'); }

언어 파일 퍼블리싱

패키지의 언어 파일을 애플리케이션의 lang/vendor 디렉토리에 퍼블리싱하고 싶다면 서비스 프로바이더의 publishes 메서드를 사용하세요. courier 패키지를 예로 들면 다음과 같습니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier'); $this->publishes([ __DIR__.'/../lang' => $this->app->langPath('vendor/courier'), ]); }

이제 사용자가 vendor:publish Artisan 명령어를 실행하면 언어 파일이 지정된 위치로 복사됩니다.

패키지의 를 Laravel에 등록하려면 뷰 파일이 어디 있는지 알려줘야 합니다. 서비스 프로바이더의 loadViewsFrom 메서드를 사용하면 됩니다. 이 메서드는 뷰 템플릿 경로와 패키지 이름, 두 가지 인자를 받습니다. 패키지 이름이 courier라면 boot 메서드에 다음과 같이 추가합니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier'); }

패키지 뷰는 패키지::뷰이름 형식으로 참조합니다. 뷰 경로가 등록되고 나면 아래처럼 courier 패키지의 dashboard 뷰를 로드할 수 있습니다:

Route::get('/dashboard', function () { return view('courier::dashboard'); });

패키지 뷰 오버라이드

loadViewsFrom 메서드를 사용하면 Laravel은 뷰를 두 곳에서 탐색합니다. 먼저 애플리케이션의 resources/views/vendor 디렉토리를 확인하고, 거기에 없으면 loadViewsFrom에서 지정한 패키지 디렉토리를 확인합니다.

예를 들어 courier 패키지의 뷰를 커스터마이즈하고 싶다면, resources/views/vendor/courier 디렉토리에 수정된 뷰 파일을 두면 됩니다. 이 구조 덕분에 패키지 사용자는 패키지 코드를 건드리지 않고도 뷰를 자유롭게 재정의할 수 있습니다.

뷰 퍼블리싱

사용자가 뷰를 수정할 수 있도록 resources/views/vendor 디렉토리로 퍼블리싱하고 싶다면 publishes 메서드를 사용하세요:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier'); $this->publishes([ __DIR__.'/../resources/views' => resource_path('views/vendor/courier'), ]); }

이제 사용자가 vendor:publish Artisan 명령어를 실행하면 뷰 파일이 지정된 위치로 복사됩니다.

뷰 컴포넌트

Blade 컴포넌트를 사용하는 패키지를 개발하거나 컴포넌트를 일반적이지 않은 디렉토리에 배치하는 경우, 컴포넌트 클래스와 HTML 태그 별칭을 수동으로 등록해야 Laravel이 컴포넌트를 찾을 수 있습니다. 보통 서비스 프로바이더의 boot 메서드에서 등록합니다:

use Illuminate\Support\Facades\Blade; use VendorPackage\View\Components\AlertComponent; /** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { Blade::component('package-alert', AlertComponent::class); }

컴포넌트를 등록하면 태그 별칭으로 렌더링할 수 있습니다:

<x-package-alert/>

패키지 컴포넌트 자동 로드

componentNamespace 메서드를 사용하면 네임스페이스 규칙에 따라 컴포넌트 클래스를 자동으로 로드할 수 있습니다. 예를 들어 Nightshade 패키지에 Nightshade\Views\Components 네임스페이스 안에 CalendarColorPicker 컴포넌트가 있다면:

use Illuminate\Support\Facades\Blade; /** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade'); }

이렇게 하면 패키지이름:: 문법으로 패키지 컴포넌트를 사용할 수 있습니다:

<x-nightshade::calendar /> <x-nightshade::color-picker />

Blade는 컴포넌트 이름을 파스칼 케이스로 변환하여 대응하는 클래스를 자동으로 찾습니다. 하위 디렉토리는 "점(dot) 표기법"으로도 지원됩니다.

익명 컴포넌트

패키지에 익명 컴포넌트가 포함되어 있다면, loadViewsFrom 메서드에서 지정한 뷰 디렉토리 내의 components 폴더 안에 배치해야 합니다. 그런 다음 패키지의 뷰 네임스페이스를 컴포넌트 이름 앞에 붙여 렌더링합니다:

<x-courier::alert />

"About" Artisan 명령어

Laravel의 기본 제공 about Artisan 명령어는 애플리케이션 환경과 설정 정보를 요약해서 보여줍니다. 패키지는 AboutCommand 클래스를 통해 이 명령어의 출력에 추가 정보를 붙일 수 있습니다. 보통 서비스 프로바이더의 boot 메서드에서 추가합니다:

use Illuminate\Foundation\Console\AboutCommand; /** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']); }

명령어

패키지의 Artisan 명령어를 Laravel에 등록하려면 commands 메서드를 사용하세요. 이 메서드는 명령어 클래스 이름의 배열을 받습니다. 등록된 명령어는 Artisan CLI를 통해 실행할 수 있습니다:

use Courier\Console\Commands\InstallCommand; use Courier\Console\Commands\NetworkCommand; /** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { if ($this->app->runningInConsole()) { $this->commands([ InstallCommand::class, NetworkCommand::class, ]); } }

Optimize 명령어

Laravel의 optimize 명령어는 설정, 이벤트, 라우트, 뷰를 캐시합니다. optimizes 메서드를 사용하면 optimizeoptimize:clear 명령어 실행 시 함께 호출될 패키지 전용 Artisan 명령어를 등록할 수 있습니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { if ($this->app->runningInConsole()) { $this->optimizes( optimize: 'package:optimize', clear: 'package:clear-optimizations', ); } }

Reload 명령어

Laravel의 reload 명령어는 실행 중인 서비스를 종료하여 시스템 프로세스 모니터가 자동으로 재시작할 수 있게 합니다. reloads 메서드를 사용하면 reload 명령어 실행 시 함께 호출될 패키지 전용 Artisan 명령어를 등록할 수 있습니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { if ($this->app->runningInConsole()) { $this->reloads('package:reload'); } }

공개 에셋

패키지에 JavaScript, CSS, 이미지 등의 에셋이 포함되어 있다면 서비스 프로바이더의 publishes 메서드를 사용해 애플리케이션의 public 디렉토리에 퍼블리싱할 수 있습니다. 아래 예시에서는 관련 에셋을 묶어 쉽게 퍼블리싱할 수 있도록 public 태그도 함께 지정합니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { $this->publishes([ __DIR__.'/../public' => public_path('vendor/courier'), ], 'public'); }

이제 사용자가 vendor:publish 명령어를 실행하면 에셋이 지정된 위치로 복사됩니다. 패키지가 업데이트될 때마다 에셋을 덮어써야 하는 경우가 많으므로, --force 플래그를 함께 사용할 수 있습니다:

php artisan vendor:publish --tag=public --force

파일 그룹 퍼블리싱

패키지의 에셋과 리소스를 개별적으로 퍼블리싱할 수 있게 하고 싶을 때가 있습니다. 예를 들어 에셋 파일 없이 설정 파일만 퍼블리싱하도록 허용하고 싶은 경우입니다. 이럴 때는 publishes 메서드를 호출할 때 태그를 붙여서 그룹을 정의하면 됩니다. 아래 예시는 courier 패키지의 서비스 프로바이더 boot 메서드에서 courier-configcourier-migrations 두 가지 그룹을 정의하는 방법입니다:

/** * 패키지 서비스를 부트스트랩합니다. */ public function boot(): void { $this->publishes([ __DIR__.'/../config/package.php' => config_path('package.php') ], 'courier-config'); $this->publishesMigrations([ __DIR__.'/../database/migrations/' => database_path('migrations') ], 'courier-migrations'); }

이제 사용자는 태그를 지정해 원하는 그룹만 퍼블리싱할 수 있습니다:

php artisan vendor:publish --tag=courier-config

--provider 플래그를 사용하면 해당 서비스 프로바이더가 정의한 모든 퍼블리싱 파일을 한 번에 퍼블리싱할 수도 있습니다:

php artisan vendor:publish --provider="Your\Package\ServiceProvider"

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 7월 17일