자동으로 인라인된 코드의 함정 피하기

게시 됨: 2022-03-10
빠른 요약 ↬ 정적 리소스를 통해 코드를 제공하는 것과 달리 인라인 CSS 또는 JS 코드를 과도하게 사용하면 사이트 성능이 저하될 수 있습니다. 이 기사에서는 인라인 코드가 너무 많다는 단점을 피하면서 대신 정적 파일을 통해 동적 코드를 로드하는 방법을 배웁니다.

인라인은 파일 내용을 HTML 문서에 직접 포함하는 프로세스입니다. CSS 파일은 style 요소 내부에 인라인될 수 있고 JavaScript 파일은 script 요소 내부에 인라인될 수 있습니다.

 <style> /* CSS contents here */ </style> <script> /* JS contents here */ </script>

HTML 출력에 이미 있는 코드를 인쇄함으로써 인라인은 렌더링 차단 요청을 피하고 페이지가 렌더링되기 전에 코드를 실행합니다. 따라서 사이트의 인지된 성능(즉, 페이지가 사용 가능하게 되는 데 걸리는 시간)을 개선하는 데 유용합니다. 예를 들어 사이트(약 14kb)를 인라인으로 로드할 때 즉시 전달되는 데이터 버퍼를 사용할 수 있습니다. 스크롤 없이 볼 수 있는 콘텐츠의 스타일(이전 Smashing Magazine 사이트에서 수행한 대로), 글꼴 크기, 레이아웃 너비 및 높이를 포함하여 나머지 데이터가 전달될 때 튀는 레이아웃이 다시 렌더링되는 것을 방지하는 중요한 스타일 .

그러나 과도하게 코드를 인라인하면 사이트 성능에 부정적인 영향을 줄 수도 있습니다. 코드를 캐시할 수 없기 때문에 동일한 콘텐츠가 클라이언트에 반복적으로 전송되고 서비스 워커를 통해 사전 캐시될 수 없습니다. 콘텐츠 전송 네트워크에서 캐시되고 액세스됩니다. 또한 CSP(콘텐츠 보안 정책)를 구현할 때 인라인 스크립트는 안전하지 않은 것으로 간주됩니다. 그런 다음 사이트 로드를 더 빠르게 하지만 가능한 한 많이 피하는 CSS 및 JS의 중요한 부분을 인라인하는 합리적인 전략을 만듭니다.

인라인을 피하기 위해 이 기사에서는 인라인 코드를 정적 자산으로 변환하는 방법을 탐구합니다. HTML 출력에 코드를 인쇄하는 대신 디스크에 저장하고(정적 파일을 효과적으로 생성) 해당하는 <script> 또는 <link> 태그를 사용하여 파일을 로드합니다.

시작하자!

추천 자료 : 프로세스로서의 WordPress 보안

점프 후 더! 아래에서 계속 읽기 ↓

인라인을 피해야 하는 경우

일부 코드를 인라인해야 하는지 여부를 설정하는 마법 같은 방법은 없지만 일부 코드가 인라인되어서는 안 되는 경우, 즉 큰 덩어리의 코드가 포함되는 경우와 즉시 필요하지 않은 경우에 매우 분명할 수 있습니다.

예를 들어 WordPress 사이트는 JavaScript 템플릿을 인라인하여 미디어 관리자를 렌더링하고(미디어 라이브러리 페이지에서 /wp-admin/upload.php 에 액세스할 수 있음) 상당한 양의 코드를 인쇄합니다.

미디어 라이브러리 페이지의 소스 코드 스크린샷
WordPress 미디어 관리자에 의해 인라인된 JavaScript 템플릿.

전체 43kb를 차지하는 이 코드 조각의 크기는 무시할 수 없으며 페이지 맨 아래에 있기 때문에 즉시 필요하지 않습니다. 따라서 대신 정적 자산을 통해 이 코드를 제공하거나 HTML 출력 내부에 인쇄하는 것이 합리적입니다.

인라인 코드를 정적 자산으로 변환하는 방법을 다음에서 살펴보겠습니다.

정적 파일 생성 트리거

내용(인라인할 내용)이 정적 파일에서 온 경우 코드를 인라인하는 대신 해당 정적 파일을 요청하는 것 외에는 할 일이 많지 않습니다.

그러나 동적 코드의 경우 내용이 포함된 정적 파일을 생성하는 방법/시기를 계획해야 합니다. 예를 들어 사이트에서 구성 옵션(예: 색 구성표 또는 배경 이미지 변경)을 제공하는 경우 새 값이 포함된 파일은 언제 생성되어야 합니까? 동적 코드에서 정적 파일을 생성할 수 있는 다음 기회가 있습니다.

  1. 요청 시
    사용자가 콘텐츠에 처음 액세스할 때.
  2. 변경 시
    동적 코드의 소스(예: 구성 값)가 변경된 경우.

먼저 요청에 따라 고려해 보겠습니다. 사용자가 사이트에 처음 액세스할 때 /index.html 을 통해 정적 파일(예: header-colors.css )이 아직 존재하지 않으므로 그때 생성해야 합니다. 이벤트 순서는 다음과 같습니다.

  1. 사용자가 /index.html 을 요청합니다.
  2. 요청을 처리할 때 서버는 header-colors.css 파일이 있는지 확인합니다. 그렇지 않기 때문에 소스 코드를 얻고 디스크에 파일을 생성합니다.
  3. <link rel="stylesheet" type="text/css" href="/staticfiles/header-colors.css"> 태그를 포함하여 클라이언트에 대한 응답을 반환합니다.
  4. 브라우저는 header-colors.css 를 포함하여 페이지에 포함된 모든 리소스를 가져옵니다.
  5. 그때까지 이 파일이 존재하므로 제공됩니다.

그러나 이벤트의 순서도 달라 만족스럽지 못한 결과를 초래할 수도 있습니다. 예를 들어:

  1. 사용자가 /index.html 을 요청합니다.
  2. 이 파일은 이미 브라우저(또는 다른 프록시 또는 서비스 워커를 통해)에 캐시되어 있으므로 요청이 서버로 전송되지 않습니다.
  3. 브라우저는 header-colors.css 를 포함하여 페이지에 포함된 모든 리소스를 가져옵니다. 그러나 이 이미지는 브라우저에 캐시되지 않으므로 요청이 서버로 전송됩니다.
  4. 서버는 아직 header-colors.css 를 생성하지 않았습니다(예: 방금 다시 시작됨).
  5. 404를 반환합니다.

또는 /index.html 을 요청할 때가 아니라 /header-colors.css 자체를 요청할 때 header-colors.css 를 생성할 수 있습니다. 그러나 이 파일이 처음에는 존재하지 않기 때문에 요청은 이미 404로 처리됩니다. 이 파일을 해킹하고 헤더를 변경하여 상태 코드를 200으로 변경하고 이미지 내용을 반환하더라도 이것은 일을 하는 끔찍한 방법이므로 우리는 이 가능성을 즐기지 않을 것입니다(우리는 이것보다 훨씬 낫습니다!)

소스가 변경된 후 정적 파일을 생성하는 옵션만 남습니다.

소스 변경 시 정적 파일 생성

사용자 종속 및 사이트 종속 소스 모두에서 동적 코드를 생성할 수 있습니다. 예를 들어 테마에서 사이트의 배경 이미지를 변경할 수 있고 해당 옵션이 사이트의 관리자에 의해 구성된 경우 배포 프로세스의 일부로 정적 파일을 생성할 수 있습니다. 반면에 사이트에서 사용자가 프로필의 배경 이미지를 변경할 수 있도록 허용하는 경우 런타임에 정적 파일을 생성해야 합니다.

간단히 말해서 다음 두 가지 경우가 있습니다.

  1. 사용자 구성
    사용자가 구성을 업데이트할 때 프로세스가 트리거되어야 합니다.
  2. 사이트 구성
    이 프로세스는 관리자가 사이트의 구성을 업데이트할 때 또는 사이트를 배포하기 전에 트리거되어야 합니다.

두 가지 경우를 독립적으로 고려한다면 #2의 경우 우리가 원하는 모든 기술 스택에서 프로세스를 설계할 수 있습니다. 그러나 우리는 두 가지 다른 솔루션을 구현하는 것이 아니라 두 가지 경우를 모두 해결할 수 있는 고유한 솔루션을 구현하고 싶습니다. 그리고 #1부터 정적 파일을 생성하는 프로세스가 실행 중인 사이트에서 트리거되어야 하므로 사이트가 실행되는 동일한 기술 스택을 중심으로 이 프로세스를 설계하는 것이 중요합니다.

프로세스를 설계할 때 코드는 #1과 #2의 특정 상황을 처리해야 합니다.

  • 버전 관리
    새로운 정적 파일 생성 시 이전 파일을 무효화하려면 "버전" 매개변수를 사용하여 정적 파일에 액세스해야 합니다. #2는 사이트와 동일한 버전 관리를 가질 수 있지만 #1은 각 사용자에 대해 동적 버전을 사용해야 하며 데이터베이스에 저장될 수 있습니다.
  • 생성된 파일의 위치
    #2는 전체 사이트에 대한 고유한 정적 파일(예: /staticfiles/header-colors.css )을 생성하는 반면 #1은 각 사용자에 대한 정적 파일(예: /staticfiles/users/leo/header-colors.css )을 생성합니다.
  • 트리거 이벤트
    #1의 경우 정적 파일이 런타임에 실행되어야 하지만 #2의 경우 스테이징 환경에서 빌드 프로세스의 일부로 실행할 수도 있습니다.
  • 배포 및 배포
    #2의 정적 파일은 사이트의 배포 번들 내부에 매끄럽게 통합될 수 있으므로 문제가 없습니다. 그러나 #1의 정적 파일은 할 수 없으므로 프로세스는 로드 밸런서 뒤에 있는 여러 서버와 같은 추가 문제를 처리해야 합니다(정적 파일은 1개의 서버에서만 생성됩니까 아니면 모든 서버에서 생성되며 어떻게 생성됩니까?).

다음으로 프로세스를 설계하고 구현해 보겠습니다. 생성될 각 정적 파일에 대해 파일의 메타데이터가 포함된 개체를 만들고 동적 소스에서 콘텐츠를 계산한 다음 마지막으로 정적 파일을 디스크에 저장해야 합니다. 아래 설명을 안내하는 사용 사례로 다음 정적 파일을 생성합니다.

  1. header-colors.css , 데이터베이스에 저장된 값의 일부 스타일
  2. 일부 변수 아래에 사용자 데이터가 있는 JSON 개체를 포함하는 welcomeuser-data.js : window.welcomeUserData = {name: "Leo"}; .

아래에서는 PHP 및 WordPress 기능을 기반으로 스택을 만들어야 하는 WordPress용 정적 파일을 생성하는 프로세스를 설명합니다. 배포 전에 정적 파일을 생성하는 기능은 이전 기사에서 설명한 대로 단축 코드 [create_static_files] 를 실행하는 특수 페이지를 로드하여 트리거할 수 있습니다.

더 읽어 보기: 서비스 워커 만들기: 사례 연구

파일을 객체로 표현하기

파일을 모든 해당 속성을 가진 PHP 객체로 모델링해야 하므로 디스크의 특정 위치(예: /staticfiles/ 또는 /staticfiles/users/leo/ 아래)에 파일을 저장하고 요청 방법을 알 수 있습니다. 결과적으로 파일. 이를 위해 파일의 메타데이터(파일 이름, 디렉토리, 유형: "css" 또는 "js", 버전 및 다른 리소스에 대한 종속성)와 해당 콘텐츠를 모두 반환하는 Resource 인터페이스를 만듭니다.

 interface Resource { function get_filename(); function get_dir(); function get_type(); function get_version(); function get_dependencies(); function get_content(); }

코드를 유지 관리하고 재사용할 수 있도록 만들기 위해 SOLID 원칙을 따릅니다. 이 원칙에 따라 모든 리소스 구현이 상속할 추상 클래스 ResourceBase 에서 시작하여 점진적으로 속성을 추가하는 리소스에 대한 개체 상속 체계를 설정합니다.

 abstract class ResourceBase implements Resource { function get_dependencies() { // By default, a file has no dependencies return array(); } }

SOLID를 따라 속성이 다를 때마다 하위 클래스를 만듭니다. 앞서 언급했듯이 생성된 정적 파일의 위치와 요청하는 버전은 사용자 또는 사이트 구성에 대한 파일에 따라 다릅니다.

 abstract class UserResourceBase extends ResourceBase { function get_dir() { // A different file and folder for each user $user = wp_get_current_user(); return "/staticfiles/users/{$user->user_login}/"; } function get_version() { // Save the resource version for the user under her meta data. // When the file is regenerated, must execute `update_user_meta` to increase the version number $user_id = get_current_user_id(); $meta_key = "resource_version_".$this->get_filename(); return get_user_meta($user_id, $meta_key, true); } } abstract class SiteResourceBase extends ResourceBase { function get_dir() { // All files are placed in the same folder return "/staticfiles/"; } function get_version() { // Same versioning as the site, assumed defined under a constant return SITE_VERSION; } }

마지막으로, 마지막 수준에서 생성하려는 파일에 대한 객체를 구현하고 get_content 함수를 통해 파일 이름, 파일 유형 및 동적 코드를 추가합니다.

 class HeaderColorsSiteResource extends SiteResourceBase { function get_filename() { return "header-colors"; } function get_type() { return "css"; } function get_content() { return sprintf( " .site-title a { color: #%s; } ", esc_attr(get_header_textcolor()) ); } } class WelcomeUserDataUserResource extends UserResourceBase { function get_filename() { return "welcomeuser-data"; } function get_type() { return "js"; } function get_content() { $user = wp_get_current_user(); return sprintf( "window.welcomeUserData = %s;", json_encode( array( "name" => $user->display_name ) ) ); } }

이를 통해 파일을 PHP 객체로 모델링했습니다. 다음으로 디스크에 저장해야 합니다.

정적 파일을 디스크에 저장

파일을 디스크에 저장하는 것은 언어에서 제공하는 기본 기능을 통해 쉽게 수행할 수 있습니다. PHP의 경우 fwrite 함수를 통해 수행됩니다. 또한 디스크에 있는 파일에 대한 절대 경로와 사이트 루트에 대한 상대 경로를 제공하는 함수가 있는 ResourceUtils 유틸리티 클래스를 만듭니다.

 class ResourceUtils { protected static function get_file_relative_path($fileObject) { return $fileObject->get_dir().$fileObject->get_filename().".".$fileObject->get_type(); } static function get_file_path($fileObject) { // Notice that we must add constant WP_CONTENT_DIR to make the path absolute when saving the file return WP_CONTENT_DIR.self::get_file_relative_path($fileObject); } } class ResourceGenerator { static function save($fileObject) { $file_path = ResourceUtils::get_file_path($fileObject); $handle = fopen($file_path, "wb"); $numbytes = fwrite($handle, $fileObject->get_content()); fclose($handle); } }

그런 다음 소스가 변경되고 정적 파일을 다시 생성해야 할 때마다 파일을 나타내는 개체를 매개 변수로 전달하여 ResourceGenerator::save 를 실행합니다. 아래 코드는 "header-colors.css" 및 "welcomeuser-data.js" 파일을 재생성하고 디스크에 저장합니다.

 // When need to regenerate header-colors.css, execute: ResourceGenerator::save(new HeaderColorsSiteResource()); // When need to regenerate welcomeuser-data.js, execute: ResourceGenerator::save(new WelcomeUserDataUserResource());

일단 존재하면 <script><link> 태그를 통해 로드할 파일을 대기열에 넣을 수 있습니다.

정적 파일을 대기열에 추가

정적 파일을 대기열에 wp_enqueue_scriptwp_enqueue_style 함수를 통해 WordPress의 리소스를 대기열에 넣는 것과 다르지 않습니다. 그런 다음 모든 객체 인스턴스를 반복하고 get_type() 값이 "js" 또는 "css" 중 하나인지에 따라 하나 또는 다른 후크를 사용합니다.

먼저 파일의 URL을 제공하고 유형이 JS 또는 CSS인지 알려주는 유틸리티 함수를 추가합니다.

 class ResourceUtils { // Continued from above... static function get_file_url($fileObject) { // Add the site URL before the file path return get_site_url().self::get_file_relative_path($fileObject); } static function is_css($fileObject) { return $fileObject->get_type() == "css"; } static function is_js($fileObject) { return $fileObject->get_type() == "js"; } }

ResourceEnqueuer 클래스의 인스턴스에는 로드해야 하는 모든 파일이 포함됩니다. 호출될 때 해당 함수 enqueue_scriptsenqueue_styles 는 해당 WordPress 함수(각각 wp_enqueue_scriptwp_enqueue_style )를 실행하여 대기열에 넣습니다.

 class ResourceEnqueuer { protected $fileObjects; function __construct($fileObjects) { $this->fileObjects = $fileObjects; } protected function get_file_properties($fileObject) { $handle = $fileObject->get_filename(); $url = ResourceUtils::get_file_url($fileObject); $dependencies = $fileObject->get_dependencies(); $version = $fileObject->get_version(); return array($handle, $url, $dependencies, $version); } function enqueue_scripts() { $jsFileObjects = array_map(array(ResourceUtils::class, 'is_js'), $this->fileObjects); foreach ($jsFileObjects as $fileObject) { list($handle, $url, $dependencies, $version) = $this->get_file_properties($fileObject); wp_register_script($handle, $url, $dependencies, $version); wp_enqueue_script($handle); } } function enqueue_styles() { $cssFileObjects = array_map(array(ResourceUtils::class, 'is_css'), $this->fileObjects); foreach ($cssFileObjects as $fileObject) { list($handle, $url, $dependencies, $version) = $this->get_file_properties($fileObject); wp_register_style($handle, $url, $dependencies, $version); wp_enqueue_style($handle); } } }

마지막으로 각 파일을 나타내는 PHP 객체 목록을 사용하여 ResourceEnqueuer 클래스의 객체를 인스턴스화하고 인큐잉을 실행하기 위해 WordPress 후크를 추가합니다.

 // Initialize with the corresponding object instances for each file to enqueue $fileEnqueuer = new ResourceEnqueuer( array( new HeaderColorsSiteResource(), new WelcomeUserDataUserResource() ) ); // Add the WordPress hooks to enqueue the resources add_action('wp_enqueue_scripts', array($fileEnqueuer, 'enqueue_scripts')); add_action('wp_print_styles', array($fileEnqueuer, 'enqueue_styles'));

그게 다야: 대기열에 넣으면 클라이언트에서 사이트를 로드할 때 정적 파일이 요청됩니다. 인라인 코드를 인쇄하지 않고 대신 정적 리소스를 로드하는 데 성공했습니다.

다음으로 추가적인 성능 향상을 위해 몇 가지 개선 사항을 적용할 수 있습니다.

추천 자료 : PHPUnit을 사용한 WordPress 플러그인 자동 테스트 소개

파일을 함께 번들링

HTTP/2가 파일 번들링의 필요성을 줄였지만 여전히 사이트를 더 빠르게 만듭니다. 파일 압축(예: GZip을 통한)이 더 효과적일 것이고 브라우저(예: Chrome)가 많은 리소스를 처리하는 더 큰 오버헤드를 갖기 때문입니다. .

지금까지 파일을 PHP 객체로 모델링하여 이 객체를 다른 프로세스에 대한 입력으로 취급할 수 있습니다. 특히, 우리는 동일한 유형의 모든 파일을 함께 묶고 모든 독립 파일 대신 번들 버전을 제공하기 위해 위의 동일한 프로세스를 반복할 수 있습니다. 이를 위해 $fileObjects 아래의 모든 리소스에서 콘텐츠를 간단히 추출하고 다시 인쇄하여 모든 리소스의 모든 콘텐츠를 집계하는 get_content 함수를 만듭니다.

 abstract class SiteBundleBase extends SiteResourceBase { protected $fileObjects; function __construct($fileObjects) { $this->fileObjects = $fileObjects; } function get_content() { $content = ""; foreach ($this->fileObjects as $fileObject) { $content .= $fileObject->get_content().PHP_EOL; } return $content; } }

이 파일에 대한 클래스를 생성하여 모든 파일을 bundled-styles.css 파일로 묶을 수 있습니다.

 class StylesSiteBundle extends SiteBundleBase { function get_filename() { return "bundled-styles"; } function get_type() { return "css"; } }

마지막으로 모든 독립 리소스 대신 이전과 같이 번들 파일을 단순히 대기열에 추가합니다. CSS의 경우 header-colors.css , background-image.cssfont-sizes.css 파일을 포함하는 번들을 생성합니다. 이 번들에 대해 각 파일에 대한 PHP 객체로 StylesSiteBundle 을 간단히 인스턴스화합니다(마찬가지로 JS를 생성할 수 있습니다. 번들 파일):

 $fileObjects = array( // CSS new HeaderColorsSiteResource(), new BackgroundImageSiteResource(), new FontSizesSiteResource(), // JS new WelcomeUserDataUserResource(), new UserShoppingItemsUserResource() ); $cssFileObjects = array_map(array(ResourceUtils::class, 'is_css'), $fileObjects); $jsFileObjects = array_map(array(ResourceUtils::class, 'is_js'), $fileObjects); // Use this definition of $fileEnqueuer instead of the previous one $fileEnqueuer = new ResourceEnqueuer( array( new StylesSiteBundle($cssFileObjects), new ScriptsSiteBundle($jsFileObjects) ) );

그게 다야 이제 많은 대신 하나의 JS 파일과 하나의 CSS 파일만 요청할 것입니다.

인지된 성능에 대한 최종 개선에는 즉시 필요하지 않은 자산 로드를 지연하여 자산의 우선 순위를 지정하는 것이 포함됩니다. 이 문제는 다음에 다루도록 하겠습니다.

JS 리소스에 대한 async / defer 속성

async 속성을 추가하고 <script> 태그에 defer 을 추가하여 JavaScript 파일이 다운로드, 구문 분석 및 실행되는 시기를 변경하여 중요한 JavaScript의 우선 순위를 지정하고 중요하지 않은 모든 항목을 가능한 한 늦게 푸시하여 사이트의 명백한 로딩을 줄일 수 있습니다. 시각.

이 기능을 구현하려면 SOLID 원칙에 따라 is_asyncis_defer 함수를 포함하는 새 인터페이스 JSResource ( Resource 에서 상속)를 만들어야 합니다. 그러나 이것은 결국 이러한 속성도 지원하는 <style> 태그에 대한 문을 닫습니다. 따라서 적응성을 염두에 두고 보다 개방적인 접근 방식을 취합니다. Resource 인터페이스에 일반 메서드 get_attributes 를 추가하여 두 속성 모두에 대해 모든 속성(이미 존재하거나 아직 개발되지 않음)에 <script> 하게 추가할 수 있습니다. <script><link> 태그:

 interface Resource { // Continued from above... function get_attributes(); } abstract class ResourceBase implements Resource { // Continued from above... function get_attributes() { // By default, no extra attributes return ''; } }

WordPress는 대기열에 추가된 리소스에 추가 속성을 추가하는 쉬운 방법을 제공하지 않으므로 add_script_tag_attributes 함수를 통해 태그 내부의 문자열을 대체하는 후크를 추가하여 다소 해키한 방식으로 수행합니다.

 class ResourceEnqueuerUtils { protected static tag_attributes = array(); static function add_tag_attributes($handle, $attributes) { self::tag_attributes[$handle] = $attributes; } static function add_script_tag_attributes($tag, $handle, $src) { if ($attributes = self::tag_attributes[$handle]) { $tag = str_replace( " src='${src}'>", " src='${src}' ".$attributes.">", $tag ); } return $tag; } } // Initize by connecting to the WordPress hook add_filter( 'script_loader_tag', array(ResourceEnqueuerUtils::class, 'add_script_tag_attributes'), PHP_INT_MAX, 3 );

해당 개체 인스턴스를 생성할 때 리소스에 대한 속성을 추가합니다.

 abstract class ResourceBase implements Resource { // Continued from above... function __construct() { ResourceEnqueuerUtils::add_tag_attributes($this->get_filename(), $this->get_attributes()); } }

마지막으로 welcomeuser-data.js 리소스를 즉시 실행할 필요가 없다면 defer 로 설정할 수 있습니다.

 class WelcomeUserDataUserResource extends UserResourceBase { // Continued from above... function get_attributes() { return "defer='defer'"; } }

지연된 상태로 로드되기 때문에 스크립트는 나중에 로드되어 사용자가 사이트와 상호 작용할 수 있는 시점을 앞당깁니다. 성능 향상과 관련하여 이제 모든 준비가 완료되었습니다!

긴장을 풀기 전에 해결해야 할 한 가지 문제가 남아 있습니다. 사이트가 여러 서버에서 호스팅되면 어떻게 됩니까?

로드 밸런서 뒤에 있는 여러 서버 다루기

우리 사이트가 로드 밸런서 뒤의 여러 사이트에서 호스팅되고 사용자 구성 종속 파일이 재생성되는 경우 요청을 처리하는 서버는 어떻게든 재생성된 정적 파일을 다른 모든 서버에 업로드해야 합니다. 그렇지 않으면 다른 서버가 그 순간부터 해당 파일의 오래된 버전을 제공합니다. 어떻게 합니까? 서버가 서로 통신하도록 하는 것은 복잡할 뿐만 아니라 궁극적으로 실현 불가능할 수 있습니다. 사이트가 다른 지역의 수백 대의 서버에서 실행되면 어떻게 될까요? 분명히 이것은 선택 사항이 아닙니다.

내가 생각해낸 솔루션은 간접 참조 수준을 추가하는 것입니다. 사이트 URL에서 정적 파일을 요청하는 대신 AWS S3 버킷과 같은 클라우드 위치에서 요청합니다. 그런 다음 파일을 재생성하면 서버가 즉시 새 파일을 S3에 업로드하고 거기에서 제공합니다. 이 솔루션의 구현은 이전 기사 AWS S3를 통해 여러 서버 간에 데이터 공유에 설명되어 있습니다.

결론

이 기사에서는 JS 및 CSS 코드를 인라인하는 것이 항상 이상적인 것은 아니라는 점을 고려했습니다. 그 이유는 코드가 클라이언트에 반복적으로 전송되어야 하므로 코드 양이 많을 경우 성능이 저하될 수 있기 때문입니다. 예를 들어 WordPress가 미디어 관리자를 인쇄하기 위해 43kb의 스크립트를 로드하는 방법을 보았습니다. 이 스크립트는 순수한 JavaScript 템플릿이고 정적 리소스로 완벽하게 로드될 수 있습니다.

따라서 우리는 동적 JS 및 CSS 인라인 코드를 정적 리소스로 변환하여 웹사이트를 더 빠르게 만드는 방법을 고안했습니다. 이는 여러 수준(클라이언트, 서비스 워커, CDN에서)에서 캐싱을 향상시키고 모든 파일을 함께 묶을 수 있습니다. 출력을 압축할 때 비율을 개선하고(예: GZip을 통해) 브라우저에서 여러 리소스를 동시에 처리하는 것으로 인한 오버헤드를 방지하기 위해(예: Chrome에서) 하나의 JS/CSS 리소스로 추가하여 속성을 async 으로 추가하거나 defer 수 있습니다. 사용자 상호 작용 속도를 높이기 위해 <script> 태그에 추가하여 사이트의 명백한 로딩 시간을 개선합니다.

유익한 부작용으로 코드를 정적 리소스로 분할하면 HTML의 큰 덩어리 대신 코드 단위를 처리하여 코드의 가독성을 높일 수 있으므로 프로젝트를 더 잘 유지 관리할 수 있습니다.

우리가 개발한 솔루션은 PHP로 수행되었으며 WordPress에 대한 몇 가지 특정 코드가 포함되어 있지만 코드 자체는 매우 간단하며 SOLID 원칙에 따라 이러한 속성을 구현하는 속성 및 개체를 정의하는 인터페이스가 거의 없으며 저장하는 기능이 있습니다. 파일을 디스크로. 그 정도입니다. 최종 결과는 깨끗하고 컴팩트하며 다른 언어 및 플랫폼에 대해 간단하게 다시 만들 수 있으며 기존 프로젝트에 도입하는 것이 어렵지 않아 쉽게 성능을 얻을 수 있습니다.