>source

웹 작업자로 typescript 라이브러리를 만들려고합니다. webpack-dev-server로 내 코드를 테스트하면 모든 것이 좋아 보이지만 모든 파일이 발견되지만 npm에서 빌드를 실행하고 다른 로컬 프로젝트 (npm install/local/path)에서 lib를 사용하려고하면 GET http://localhost:8080/X.worker.js 브라우저 콘솔에서.

webpack.config.js :

const path = require('path');
module.exports = {
    devtool: 'inline-source-map',
    entry: {
        'mylib': './src/index.ts',
        'mylib.min': './src/index.ts',
    },
    output: {
        path: path.resolve(__dirname, '_bundles'),
        filename: '[name].js',
        libraryTarget: 'umd',
        library: 'mylib',
        umdNamedDefine: true
    },
    resolve: {
        extensions: ['.ts', '.tsx', '.js']
    },
    optimization: {
        minimize: true
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loader: 'awesome-typescript-loader',
                exclude: /node_modules/,
                query: {
                    declaration: false,
                }
            },
            {
                test: /\.worker\.js$/,
                use: {
                    loader: "worker-loader"
                }
            },
        ]
    }
};

tsconfig.json

{
    "compilerOptions": {
        "target": "es5",
        "module": "es6",
        "lib": [
            "webworker",
            "es2015",
            "dom"
        ],
        "moduleResolution": "node",
        "sourceMap": true,
        "strict": true,
        "alwaysStrict": true,
        "outDir": "lib",
        "resolveJsonModule": true,
        "declaration": true,
        "skipLibCheck": true,
        "allowJs": true
    },
    "include": [
        "**/*.ts",
        "**/*.tsx"
    ],
    "exclude": [
        "node_modules",
        "lib",
    ]
}

package.json

{
  "name": "mylib",
  "version": "1.0.0",
  "description": "",
  "main": "_bundles/mylib.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "webpack": "webpack",
    "build": "rm -rf ./lib && tsc",
    "serve": "webpack-dev-server",
    "clean": "rm -rf _bundles lib lib-esm",
    "newbuild": "npm run clean && tsc && tsc -m es6 --outDir lib-esm && webpack"
  },
  "repository": {
    "type": "git",
    "url": "..."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "..."
  },
  "homepage": "...e",
  "devDependencies": {
    "prettier": "^2.1.2",
    "tslint": "^6.1.3",
    "tslint-config-prettier": "^1.18.0",
    "worker-loader": "^3.0.5"
  },
  "dependencies": {
     ...
  }
}

작업자를 가져 오는 방법에 대한 예 :

import X from "worker-loader!./X";

  • 답변 # 1

    나는 몇 달 전에 똑같은 상황에 처해 있었다. 저에게 맞는 해결책을 찾았지만 먼저 왜 이런 일이 발생하는지 논의하겠습니다.

    문제 :

    여기에 3 개의 레이어가 있습니다.

    라이브러리의 개발 계층

    라이브러리의 빌드 레이어

    라이브러리 빌드를 사용하는 애플리케이션

    레이어 1은 간단합니다. 새 작업자를 만들려는 파일에서 index.ts , 당신은 당신의 import X from "worker-loader!./X" . 너의 index.ts 작업자 파일을 찾을 위치를 정확히 알고 있습니다. 이것이 바로 webpack-dev-server에서 작동하는 이유입니다.

    레이어 2는 상황이 이상 해지는 곳입니다. 작업자 파일을 처리 할 때 worker-loader , webpack은 여러 파일을 출력합니다. 당신의 구성은 말한다 filename: '[name].js' , 소스 폴더의 모든 파일에 대한 파일을 모두 출력합니다. _bundles 폴더. Webpack은 import X from "worker-loader!./X" , 가져온 파일의 대상 이름과 위치, 가져 오기를 수행하는 파일도 표시됩니다. 웹 작업자 파일의 위치를 ​​다시 작성합니다.이내에그만큼 index.js 출력 번들을순수한나머지 번들에 상대적인 경로입니다. 다음을 사용하여보다 신중하게 제어 할 수 있습니다. publicPath 작업자 로더의 옵션. 그러나 이것은 문제를 실제로 해결하지 못합니다. publicPath 3 단계로 이어지는 절대 경로로 ...

    패키지를 소비하려는 레이어 3은 문제가 발생하는 곳입니다. 어디에서 시도할지 예상 할 수 없습니다. import { makeAWorker } from 'your-library' 그들의 코드에서. 가져 오는 위치에 관계없이 빌드 파일 (소비자 앱의 node_modules에 있음)은 웹팩이 빌드에 작성한 경로를 사용합니다. index.js 작업자 파일을 찾지 만 이제 절대 경로는소비자 프로젝트와 관련하여(일반적으로 index.html이있는 위치와 같은 홈 경로), 빌드의 node_modules 폴더가 아닙니다. 따라서 소비자 앱은 작업자 파일을 어디에서 찾을 수 있는지 모릅니다.

    내 솔루션 : 약간의 해킹

    내 시나리오에서는 작업자 파일의 내용이 문자열에서 작업자를 만들고 그런 방식으로 가져올 수있을만큼 간단하다고 결정했습니다. 예를 들어 작업자 파일은 다음과 같습니다.

    // worker.ts
    // Build a worker from an anonymous function body
    export default URL.createObjectURL(
      new Blob([
        '(',
        function () {
          // actual worker content here
        }.toString(),
        ')()', ],
        { type: 'application/javascript' }
      )
    );
    
    

    그런 다음 작업자를 스폰하려는 위치에서 :

    // index.ts
    import workerScript from './worker';
    const myWorker = new Worker(workerScript, {worker_options});
    
    

    이제 더 이상 웹팩에 파일을 생성하고 올바른 가져 오기 위치를 작성하도록 요청하지 않기 때문에 작동합니다. 결국에는 작업자 스크립트를위한 별도의 파일도 번들에 포함되지 않습니다. 당신은 버릴 수 있습니다 worker-loader 전부. 너의 index.ts Blob과 해당 URL을 만들고 소비자 애플리케이션은 런타임에 동적으로 생성되는 해당 URL에서 작업자 스크립트를 찾습니다.

    참으로 해킹

    이 방법에는 몇 가지 심각한 단점이있어 단일 파일 웹팩 출력이있는 npm 패키지의 필수 부분으로 번들 웹 작업자에게 질문하게되었습니다. 문제는 작업자 스크립트 내에서 실제로 아무것도 가져올 수있는 옵션이 없다는 것입니다. 제 일꾼이 비교적 단순하다는 점에서 운이 좋았습니다. 자체적으로 종속성이없는 단일 node_module에 의존했습니다. 스크립트에 해당 모듈의 소스를 포함하는 것부터 시작했지만 동일한 외부 모듈이 필요한 여러 스크립트가 있었기 때문에 생성 될 때 작업자에게 데이터 조각으로 전달했습니다.

    import { Rainbow } from './utils';
    var data = {
      id,
      data              
      RainbowAsString: Rainbow.toString(),
    };
    myWorker.postMessage(data);
    
    

    그런 다음 작업자 내에서 간단히 RainbowAsString 함수로 돌아가서 사용하십시오. 더 자세한 내용을 알고 싶으시면 제가 만든 라이브러리 인 leaflet-topography를 확인해보세요. 들여다 src/TopoLayer.ts 작업자가 어떻게 사용되는지 확인하려면 파일을 src//workers 작업자 Blob을 설정하는 방법을 보려면 폴더를 클릭하십시오.

    결론

    더 나은 방법이 있어야한다고 생각합니다. 가능한 빠른 해결 방법 중 하나는 작업자 파일을 복사하는 복사 스크립트를 작성하는 것입니다. node_modules/yourLibrary 소비자 앱의 빌드 폴더에 추가합니다. 그러나 이것은 뛰어난 이식성을 보장하지 않으며 다른 사람들도 라이브러리가 앱과 함께 작동하도록하기 위해 동일한 작업을 수행해야합니다. 내 솔루션은 완벽하지는 않지만 단순한 작업자 스크립트에서는 작동합니다. 저는 노동자들이 스스로 수입을 할 수 있도록하는 더 강력한 솔루션에 대해 여전히 생각하고 있습니다.

    편집 : 적절한 솔루션 :

    그래서이 답변을 작성한 후 대화에 참여하도록 영감을 얻었습니다. 이것을 사용하여 라이브러리를 묶는 방법은 무엇입니까? webpack-loader 저장소에 있습니다. 분명히 webpack 5가 약 2 개월 전에 출시되었을 때 다음 구문에 대한 지원을 추가했습니다.

    new Worker(new URL('./path/to/worker.js', import.meta.url))
    
    

    나는 이것을 시도하지 않았지만 필요한 솔루션처럼 보입니다 (그리고 2 개월 전에 해킹을 할 때 필요했던 솔루션). 이것을 시도해보십시오. 작업자 스크립트와이를 가져 오는 스크립트 간의 관계를 유지하면서 라이브러리를 번들링하도록 webpack에 정확히 알려야 할 수 있습니다.

관련 자료

  • 이전 ruby on rails - distribution_reads gem은 Amazon Aurora에 대한로드 밸런싱 복제본을 지원합니까?
  • 다음 kotlin - 중복 된 else 분기를 어떻게 피할 수 있습니까?