HtmlWebpackPlugin을 사용하여 로드 오류 및 반환 처리

TL;박사
HtmlWebpackPlugin & 패키지를 불러올 때 오류가 발생할 수 있습니다. we’ve got you covered.
오류가 발생했습니다.
프로그래밍은 특히 이렇다.그러나 오류가 프로그램의 코드가 실행되기 전에 발생했을 때 이것은 좀 놀랍고 처리하기 어려울 수도 있다.
이것이 바로 내가 최근에 처리해야 할 문제이다. 이것은 클라이언트 웹 응용 프로그램에서 매우 흔히 볼 수 있는 문제일 것 같다.
내가 본 오류는 다음과 같다.
Uncaught SyntaxError: Unexpected token '<'
일부 연구를 통해 오류가 발생한 장면은 다음과 같다.
  • 사용자의 브라우저는 웹 사이트를 처음 방문할 때 페이지를 캐시합니다.사용자가 X일이 되어서야 이 사이트를 다시 방문하였다
  • 저희는 적극적으로 사이트를 개발하고
  • 을 발표했습니다.
  • 새로운 버전마다 서버
  • 에 유일한 해시가 있는 패키지를 추가합니다
  • 우리는 서버에 몇 개의 최신 버전을 저장했지만, 서버 자원이 제한되어 있기 때문에, 모든 새로운 버전이 출시됨에 따라, 우리는 가장 오래된 버전
  • 을 삭제했다
  • 이 X일째입니다. 페이지 캐시 버전을 가진 사용자는
  • 에 반갑게 왔습니다.
  • 사용자의 브라우저는 bundle.[too-old-hash].js을 가져오려고 시도했지만 서버에 존재하지 않습니다. 여러 번 배치되었기 때문에 이 이전 버전은
  • 에서 삭제되었습니다.
  • 서버는 404로 응답했고 404는 HTML 페이지
  • 입니다
  • JS 컴파일러가 HTML을 해석할 수 없음 & SyntaxError 던지기
  • 저희 응용 프로그램은 클라이언트에서 React로 나타나지만, 패키지가 없기 때문에 사용자는 빈 페이지를 볼 수 있습니다
  • 그러면 전체 응용 프로그램을 사용할 수 없기 때문에 발생하는 오류를 어떻게 처리합니까?다음은 가능한 프런트엔드 전용 솔루션을 보여 드리겠습니다.
    만약 당신이 인코딩을 좋아한다면, 당신은 sample repo with all setup but no solution implemented here을 찾을 수 있습니다.

    설치 프로그램


    우리는 webpack을 사용하여 우리의 코드를 컴파일하고 귀속시키며, HtmlWebpackPlugin을 사용하여 HTML 페이지를 생성합니다. 우리의 응용 프로그램은 최종적으로 이 페이지에서 실행될 것입니다.
    우리의 응용 프로그램은 어떤 형식이든 될 수 있다.본문은 틀은 알 수 없다.

    가능한 솔루션 및 고려 사항


    우선, 논리적으로, 우리는 bundle.[hash].js에서 어떠한 조작도 수행할 수 없습니다. 왜냐하면 이 파일은 불러올 수 없고, 실행할 때 사용할 수 없기 때문입니다.
    그럼, 우리는 어떻게 해야 합니까?응, 우리는 페이지에 내연 JS를 추가할 수 있어.그것은 시종일관 존재할 것이며, 따라서 약간의 처리를 할 수 있을 것이다.
    HTML 페이지를 만드는 데 사용되는 템플릿의 기본 위치인 src/index.ejs을 만듭니다.이 파일을 만들면 페이지를 만드는 HTML 프레임워크를 사용자 정의할 수 있습니다.
    첫 번째 천진한 시도는 HtmlWebpackPlugin 템플릿에 내장 JS를 추가하여 응용 프로그램의 스크립트 표시에 error event을 정탐하는 것입니다. 아래와 같습니다.src/index.ejs :
    <!DOCTYPE html>
    <html lang="en" dir="ltr">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Handling script loading errors with HtmlWebpackPlugin</title>
    </head>
    <body>
        <h1 id="content"></h1>
        <script>
        (function(){
            function showErrorPage() {
                // Doesn't matter for now
            }
    
            var appScript = document.querySelector('script[src^="bundle"]');
            appScript.addEventListener('error', showErrorPage);
        })();
        </script>
        <!--
        HTMLWebpackPlugin will insert bundled script here on build.
        It will look something like this:
    
        <script src="bundle.foo12.js"></script>
        -->
    </body>
    </html>
    
    그러나 이것은 작용하지 않을 것이다. 왜냐하면 내연 <script>의 코드를 실행할 때, <script src="bundle.foo12.js"></script>은 심지어 DOM에 존재하지 않는다. 왜냐하면 내연 스크립트 표시 아래에 있고 브라우저가 아직 그것을 분석하지 않았기 때문이다.알겠습니다. DOM이 준비될 때까지 기다릴게요. & 준비가 되면 같은 일을 하고 이벤트 탐지기를 추가합시다.src/index.ejs :
    <script>
    (function(){
        function showErrorPage() {
            // Doesn't matter for now
        }
    
        window.addEventListener('DOMContentLoaded', function() {
            var appScript = document.querySelector('script[src^="bundle"]');
            appScript.addEventListener('error', showErrorPage);
        });
    })();
    </script>
    
    불행하게도, 이것도 통하지 않는다. 브라우저가 우리의 패키지를 불러오려는 순수한 스크립트 표시를 보았을 때, 패키지를 즉시 가져오고 실행한 다음, HTML 해석을 복원하고, </html>에 이르면 DOMContentLoaded event을 터치하기 때문이다.
    다음은 도면입니다.

    이런 상황에서 우리는 캡처와 실행 단계가 끝나기 전에 이벤트 탐지기를 연결했다. 우리의 리셋은 영원히 촉발되지 않을 것이다.
    그래서 우리가 너무 일찍 왔거나 너무 늦게 왔나 봐요.
    이 단계에서 우리는 매우 짧은 시간 간격이나 다른 폭력 해결 방안으로 패키지의 스크립트가 DOM에 존재하는지 검사할 수 있다.
    다행히도, 이것은 필수적인 것이 아니다. 왜냐하면 Html Webpack Plugin은 우리에게 우아하고 효율적인 해결 방안을 실현하는 모든 것을 제공했기 때문이다.

    솔루션


    우리는 분명히 불러오는 사건을 감청해야 한다.
    그러나 불러오는 이벤트를 탐지할 수 있도록 가방이 언제 불러오는지 더 많은 제어를 해서 이벤트 탐지기를 즉시 추가할 수 있도록 해야 한다.
    좋아, 통제를 뛰어넘자.
    우선, Html Webpack Plugin에게 우리가 제어할 수 없는 <script>을 페이지에 주입하는 것을 원하지 않는다고 알려 드리겠습니다.webpack.config.js :
    plugins: [
        new HtmlWebpackPlugin({
            inject: false
        })
    ]
    
    현재 우리는bundle의 <script> 라벨이 아예 없기 때문에 우리의 응용 프로그램은 영원히 불러오지 않습니다.이것은 좋지 않지만, 우리는 HtmlWebpackPlugin이 우리에게 제공한 정보를 사용하여 <script> 표시를 만들 수 있습니다.src/index.ejs :
    <script>
    (function() {
        function showErrorMessage() {
            alert('Oops, something went wrong! Please reload the page.');
        }
    
        // Paths of all bundles
        var bundlesSrcs = <%= JSON.stringify(htmlWebpackPlugin.files.js) %>;
        for(var i=0; i < bundlesSrcs.length; i++) {
            // Create script tag & configure it
            var scriptTag = document.createElement('script');
            scriptTag.src = bundlesSrcs[i];
            scriptTag.addEventListener('error', showErrorMessage);
    
            // Append script tag into body 
            document.body.appendChild(scriptTag);
        }
    })();
    </script>
    
    템플릿 HtmlWebpackPlugin will pass a variable called htmlWebpackPlugin to it을 사용하는 경우여기에서 우리는 htmlWebpackPlugin.files.js을 방문합니다. 이것은 하나의 수조로 이번 운행 기간에 웹팩에서 만든 모든javascript 패키지의 경로를 포함합니다.
    이 이상한 구조인'<%= … %>'은 정보를 문서에 인쇄하는 Embedded JavaScript templating 문법에만 사용된다.
    이 예에서는 구축할 때 ['bundle.foo12.js']으로 해석됩니다.
    일단 우리가 경로 그룹을 얻게 되면, 우리는 이 그룹을 두루 훑어보고, 모든 경로에 <script> 표시를 만들 수 있다.
    새로 만든 <script>을 문서에 삽입하기 전에 오류 탐지기를 추가합니다.이번에 우리는 제때에 탐지기를 연결했기 때문에, 만약 어떤 오류가 발생하면, 그것은 촉발될 것이다.
    이 코드는 컴파일되지 않고 브라우저에 그대로 전송되기 때문에 ES5에 맞는 문법을 사용하려고 합니다.

    추가 기능: 오류 메시지에 이미지 삽입


    IRL은 브라우저의 경보 상자에 메시지를 표시하지 않고 멋진'오류 페이지'를 표시하려고 할 수도 있습니다.아마도, 우리는 오류 페이지에 그림을 표시하고 싶을 것이다.
    문제 없어요.우리의 템플릿은 충분히 유연해서 그것을 가능하게 한다.
    우선, 이미지를 처리할 수 있는 file-loader을 설치하겠습니다.terminal :
    npm install file-loader --save-dev
    
    이제 웹 팩에 이 로딩 프로그램을 사용하라고 알려 드리겠습니다.webpack.config.js :
    module: {
        rules: [
            {
                test: /\.(png|jpe?g|gif)$/i,
                loader: 'file-loader'
            }
        ]
    }
    
    이제 index.ejs 템플릿에서 다음과 같이 이미지를 직접 요청할 수 있습니다.
    <%= require('./path_to_image').default %>
    
    전체 src/index.ejs 파일입니다.
    <!DOCTYPE html>
    <html lang="en" dir="ltr">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Handling script loading errors with HtmlWebpackPlugin</title>
        <style>
            html, body, h1 {
                padding: 0;
                margin: 0;
            }
            #bundleLoadingErrorContainer {
                position: fixed;
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                background-color: #FFF;
                text-align: center;
                width: 100%;
                height: 100%;
            }
            .bundle_error_title {
                padding: 0 1.5%;
            }
        </style>
    </head>
    <body>
        <h1 id="content"></h1>
        <div id="bundleLoadingErrorContainer" style="display: none;">
            <h2 class="bundle_error_title">Oops, something went wrong. Please reload the page.</h2>
            <figure class="photo">
                <img src="<%= require('./assets/bird.jpg').default %>" width="300" height="200" alt="bird">
                <br>
                <br>
                <figcaption>
                    Photo by <a href="https://unsplash.com/@photoholgic" target="_blank" rel="external noopener">Holger Link</a> on <a href="https://unsplash.com/" target="_blank" rel="external noopener">Unsplash</a>
                </figcaption>
            </figure>
        </div>
        <script>
        (function() {
            function showErrorMessage() {
                document.getElementById('bundleLoadingErrorContainer').removeAttribute('style');
            }
    
            var bundlesSrcs = <%= JSON.stringify(htmlWebpackPlugin.files.js) %>;
            for(var i=0; i < bundlesSrcs.length; i++) {
                var scriptTag = document.createElement('script');
                scriptTag.src = bundlesSrcs[i];
                scriptTag.addEventListener('error', showErrorMessage);
    
                document.body.appendChild(scriptTag);
            }
        })();
        </script>
    </body>
    </html>
    

    결론


    도움이 됐으면 좋겠어요!최종 버전의 모든 코드는 this repo에서 찾을 수 있습니다.
    현재, 우리는 모두 완성했습니다. 당신은 잘 알려지지 않은 Chrome’s request blocking feature 테스트 오류 처리 프로그램의 작업 방식을 사용할 수 있습니다.

    좋은 웹페이지 즐겨찾기