Ember 애드온을 v2 형식으로 마이그레이션

Feb 27 2023
Polaris 에디션으로 가는 길에 Ember JS 세계에서 한 가지 주요 변경 사항이 발표되었습니다. Embroider는 Embroider와 더 넓은 JS 생태계 사이의 격차를 해소하는 것을 목표로 하는 차세대 빌드 시스템으로 일단 채택되면 많은 이점을 제공합니다. RFC에서 언급한 바와 같이: 컨텍스트 내가 작업하고 있는 애드온에는 다음 기능이 포함되어 있습니다. 그들에 대한 지식 부족.

Polaris 에디션으로 가는 길에 Ember JS 세계에서 한 가지 주요 변경 사항이 발표되었습니다. Embroider는 Embroider와 더 넓은 JS 생태계 사이의 격차를 해소하는 것을 목표로 하는 차세대 빌드 시스템으로 일단 채택되면 많은 이점을 제공합니다. RFC 에서 언급한 바와 같이 :

  • 일반적인 NPM 패키지가 될 "특별한" 애드온이 적습니다.
  • 더 빠른 빌드 및 NPM 설치.
  • Webpack 또는 Vite와 같은 기존 빌드 도구를 활용할 수 있습니다.
  • 나무 흔들기 및 코드 분할과 같이 Ember 생태계에 너무 오랫동안 부족했던 중요한 기능을 제공합니다.

문맥

내가 작업한 애드온에는 다음과 같은 기능이 포함되어 있습니다.

  • 타자기
  • 서비스
  • Ember 데이터 어댑터, 모델, 직렬 변환기
  • 구성 요소(Glimmer와 Ember Classic의 혼합)
  • 번역( ember-intl 제공 )
  • 상위 앱에 복사해야 하는 구성 요소에 사용되는 일부 공용 자산(이미지)
  • 일부 CSS( Less 를 사용하여 전처리됨 )

또한 monorepos(여기서는 Yarn Workspaces)로 작업해야 하는 것이 이번이 처음이었기 때문에 내가 직면한 문제 중 일부는 이에 대한 지식 부족과 관련이 있을 수 있습니다.

코드모드 실행

아직 완료하지 않은 경우 새 파일 트리에 대한 많은 설명을 제공하는 v1 애드온을 v2 형식으로 포팅하기 위한 마이그레이션 가이드를 읽어 보시기 바랍니다 .

다행스럽게도 v2 형식이 도입된 이후로 프로세스 속도를 높이기 위해 커뮤니티에서 몇 가지 codemods를 작성했으며 저는 ember-codemod-v1-to-v2 ( ember-addon-migrator 도 옵션이지만 저는 그렇게 했습니다. 아직 테스트하지 않음).

npx [email protected] --addon-location="packages/addon" --test-app-location="packages/test-app"

  • 애드온 패키지: 상위 앱에 제공될 것으로 예상되는 실제 애드온 코드입니다.
  • v1 형식의 더미 앱과 동일한 역할을 수행하는 테스트 앱 패키지.
  • 애드온 빌드(감시 모드 포함)
  • 테스트 앱 서버 실행
  • 테스트 앱에서 테스트 실행

번역 처리

translationsember-intl을 사용하면 프로젝트의 루트에 codemod에 의해 생략된 디렉토리가 있어 필요한 경우 번역이 누락됩니다 . translations이 문제를 해결하려면 디렉토리를 애드온의 패키지 루트로 이동한 다음 'files' 필드에 나열하여 packages/my-addon/package.json게시하고 상위 앱에서 사용할 수 있도록 해야 했습니다 .

{
  "name": "my-addon",
  "version": "0.0.13",
  "keywords": [
    "ember-addon"
  ],
  ...,
  "files": [
    "addon-main.cjs",
    "dist",
    "translations"
  ]
}

애드온은 Ember 데이터 어댑터와 함께 배송되기 때문에 상위 앱의 실행 환경에 따라 올바른 백엔드 호스트에 도달하도록 구성해야 합니다.

이전에는 다음과 같이 했습니다.

import { getOwner } from '@ember/application';

export default class BaseAdapter extends AuthorizedAdapter {
  get namespace(): string {
    return 'api/v1';
  }

  get host(): string {
    const config = getOwner(this).resolveRegistration('config:environment')['my-addon'];
    return config.backendURL;
  }
}

불행히도 이것은 v2 형식이 마법과 빌드 시간 마법이 적기 때문에 더 이상 작동하지 않았습니다. 그러나 여전히 @embroider/macros. 이 패키지를 사용하여 개체 값을 업데이트하기만 하면 올바른 호스트를 구성할 수 있었습니다 config.

import { getOwnConfig } from '@embroider/macros';

export default class BaseAdapter extends AuthorizedAdapter {
  get namespace(): string {
    return 'api/v1';
  }

  get host(): string {
    return (getOwnConfig() || {}).backendURL;
  }
}

module.exports = function (defaults) {
  let app = new EmberAddon(defaults, {
    '@embroider/macros': {
      setConfig: {
        'my-addon': {
          backendURL: process.env.BACKEND_URL || 'https://some-default.api.io'
        }
      }
    }
  });
}

공공재산 제공

실제로 애드온을 사용하는 앱에서 애드온을 연결한 후 일반적으로 애드온과 함께 제공되는 모든 이미지가 앱의 빌드에 없다는 것을 알았습니다.

애드온의 폴더에 있는 파일 public(그런데 로 이동해야 함 )은 다음 형식으로 packages/my-addon/public애드온 package.json의 메타 개체에 나열되어야 합니다.ember-addon.public-assets

{
  "name": "my-addon",
  "version": "0.0.13",
  "keywords": [
    "ember-addon"
  ],
  "ember-addon": {
    ...,
    "public-assets": {
      "./public/assets/images/tomster.png": "/my-addon/assets/images/tomster.png",
      "./public/assets/images/zoey.svg": "/my-addon/assets/images/zoey.svg"
    }
  }
  ...
}

그러나 이것은 단지 몇 개의 공개 자산을 제공하는 애드온의 경우 매우 빠를 수 있지만 많은 자산이 있는 경우 감당할 수 없을 수 있으므로 빌트인 롤업 플러그인을 추가하기 위해 열린 풀 요청이ember-addon.public-assets 있습니다. 메타 개체를 디렉터리와 동기화 상태로 유지합니다 public.

CSS 다루기

이전에 언급했듯이 이 애드온은 Less CSS를 사용하여 사전 처리된 CSS와 함께 일부 구성 요소를 제공합니다. 또한 전에는 자신의 CSS를 가져오는 구성 요소가 없었지만 addon/styles/addon.less다른 관련 파일을 가져오는 진입점 파일이 있었습니다. 모든 구성 요소를 거치지 않고 CSS를 그 옆에 배치하기 위해 지금은 단일 CSS 파일을 계속 사용하기로 했습니다. 그래서 이 시점에서 처리해야 할 두 가지 문제가 있었습니다.

  • JS 파일에서 가져오지 않은 CSS는 생략됩니다.
  • ember-cli-lessLess 파일을 처리하기 위해 더 이상 작동하지 않았습니다.

{
  "name": "my-addon",
  "version": "0.0.13",
  "keywords": [
    "ember-addon"
  ],
  ...,
  "exports": {
    ".": "./dist/index.js",
    "./*": {
      "types": "./dist/*.d.ts",
      "default": "./dist/*.js"
    },
    "./addon-main.js": "./addon-main.cjs",
    "./styles": "./dist/styles/_addon.css",
  },
}

import Application from '@ember/application';
import Resolver from 'ember-resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';

import 'my-addon/styles';

export default class App extends Application {
  modulePrefix = config.modulePrefix;
  Resolver = Resolver;
}

loadInitializers(App, config.modulePrefix);

  • 리팩토링의 경우: 모든 것이 서로 옆에 있습니다.
  • 그것은 트리 쉐이킹을 더 쉽게 만들고 죽은 CSS를 브라우저에 전달하지 않습니다.

import { readFileSync, writeFileSync } from 'fs';
import less from 'less';

import { Addon } from '@embroider/addon-dev/rollup';

const addon = new Addon({
  srcDir: 'src',
  destDir: 'dist'
});

export default {
  // This provides defaults that work well alongside `publicEntrypoints` below.
  // You can augment this if you need to.
  output: addon.output(),

  plugins: [
    // Made sure to do the preprocessing before the keepAssets plugin is ran.
    {
      name: 'less-handler',
      generateBundle() {
        const lessCode = readFileSync('src/styles/main.less', 'utf-8');
        less.render(
          lessCode,
          {
            paths: ['src/styles']
          },
          (err, rendered) => {
            if (err) {
              console.log(err);
              return;
            }
  
            const css = rendered.css;
            const filename = path.join('src', 'styles', '_addon.css');
            mkdirp.sync(path.dirname(filename));
            writeFileSync(filename, css);
          }
        );
      }
    },

    // addons are allowed to contain imports of .css files, which we want rollup
    // to leave alone and keep in the published output.
    addon.keepAssets(['**/*.css']),

  // Remaining plugins from the sample file
  ]
};

문제 해결

다음은 codemod를 실행한 후 쉽게 수정된 몇 가지 문제입니다.

  1. 선언 필드는 먼저 @babel/plugin-transform-typescript에 의해 변환되어야 합니다. 옵션을 활성화하여 수정됨 allowDeclareFields(https://babeljs.io/docs/babel-preset-typescript#allowdeclarefields)
  2. 이전 가져오기(패키지 이름이 루트임)를 상대 가져오기로 교체하는 동안 codemod는 실수로 일부 구성 요소에서 동적으로 빌드된 자산 경로를 상대 가져오기로 교체하여 일부 이미지 경로를 손상시켰습니다. 여기에서 빠른 이중 확인이 필요할 수 있습니다.
  3. ember-auto-import가 css-loader상대 경로가 있는 URL을 처리하지 못했습니다. 이것은 이 마이그레이션 컨텍스트 외부에서도 발생했던 Webpack의 알려진 문제입니다. 지금은 ( autoImport.cssLoaderOptions.urlcf.falsehttps://webpack.js.org/loaders/css-loader/#url) 문제를 해결합니다.