자 바스 크 립 트 에서 매크로 를 어떻게 사용 하 는 지 상세 하 게 설명 합 니 다.
impl Component for MyComponent {
// ...
fn view(&self) -> Html {
let onclick = self.link.callback(|_| Msg::Click);
html! {
<button onclick=onclick>{ self.props.button_text }</button>
}
}
}
JavaScript 매크로 의 한계 성Rust 와 달리 자 바스 크 립 트 자체 가 매크로 를 지원 하지 않 기 때문에 전체 도구 체인 도 매크로 를 고려 하지 않 았 습 니 다.따라서 사용자 정의 문법 을 식별 하 는 매크로 를 쓸 수 있 지만 세트 로 된 도구 체인 이 지원 되 지 않 기 때문에 가장 흔히 볼 수 있 는 VSCode 와 Typescript 등 문법 적 오 류 를 얻 을 수 있 습 니 다.마찬가지 로 babel 자체 에 사용 되 는 parser 도 확장 문법 을 지원 하지 않 습 니 다.다른 Fork 에서 Babel 이 나 오지 않 는 한.따라서 babel-plugin-macros 는 사용자 정의 문법 을 지원 하지 않 습 니 다.그러나 템 플 릿 문자열 함 수 를 통 해 우 리 는 곡선 으로 나 라 를 구 할 수 있 고 적어도 일부 문법 트 리 를 사용자 정의 하 는 능력 을 얻 을 수 있 습 니 다.JavaScript 에서 GraphQL 을 직접 작성 할 수 있 는 GraphQL 의 예 입 니 다.
import { gql } from 'graphql.macro';
const query = gql`
query User {
user(id: 5) {
lastName
...UserEntry1
}
}
`;
// ↓ ↓ ↓ ↓ ↓ ↓
const query = {
"kind": "Document",
"definitions": [{
...
Babel 플러그 인 대신 매크로 를 사용 하 는 이 유 는 무엇 입 니까?Babel 플러그 인의 능력 은 매크로 보다 훨씬 크 고 어떤 경우 에는 플러그 인 을 사용 해 야 합 니 다.매크로 가 Babel 플러그 인 보다 좋 은 점 은 매크로 의 이념 은 상 자 를 열 면 바로 사용 하 는 것 이다.React 를 사용 하 는 개발 자 는 모두 들 어 본 유명한 Create-React-app 을 믿 습 니 다.다양한 바 텀 디 테 일 을 밀봉 해 주 었 습 니 다.개발 자 는 코드 작성 에 전념 하면 됩 니 다.그러나 CRA 의 문 제 는 너무 엄격하게 봉 인 된 것 이다.바벨 플러그 인 을 사용자 정의 할 필요 가 있다 면 기본적으로 yarn react-script eject 를 실행 하여 모든 밑바닥 디 테 일 을 드 러 내야 한다.매크로 에 대해 서 는 프로젝트 의 Babel 설정 에 babel-plugin-macros 플러그 인 을 추가 하면 플러그 인 처럼 다양한 플러그 인 을 다운로드 해 야 하 는 것 이 아니 라 사용자 정의 Babel 매크로 를 완벽 하 게 지원 할 수 있 습 니 다.CRA 는 이미 babel-plugin-macros 가 내장 되 어 있 습 니 다.CRA 프로젝트 에서 임의의 Babel 매크로 를 사용 할 수 있 습 니 다.
어떻게 매크로 를 씁 니까?
소개 하 다.
하나의 매크로 는 Babel 플러그 인 과 매우 비슷 하기 때문에 Babel 플러그 인 을 어떻게 만 드 는 지 미리 알 아 보 는 것 이 도움 이 됩 니 다.Babel 플러그 인 을 어떻게 만 드 는 지 에 대해 Babel 공식 적 으로 한 권매 뉴 얼이 있 습 니 다.0 에서 Babel 플러그 인 을 만 드 는 방법 을 소개 합 니 다.Babel 플러그 인 을 어떻게 만 드 는 지 알 게 된 후에 우 리 는 먼저 매크로 를 사용 하 는 예 를 통 해 Babel 이 파일 의 매크로 를 어떻게 식별 하 는 지 소개 합 니 다.어떤 특수 한 문법 입 니까?아니면 썩 은$기 호 를 사용 합 니까?
import preval from 'preval.macro'
const one = preval`module.exports = 1 + 2 - 1 - 1`
이것 은 매우 흔히 볼 수 있 는 매크로 입 니 다.컴 파일 기간 에 문자열 의 자바 스 크 립 트 코드 를 실행 한 다음 에 실 행 된 결 과 를 해당 하 는 곳 으로 바 꾸 는 역할 을 합 니 다.예 를 들 어 위의 코드 는 컴 파일 기간 에 다음 과 같이 전 개 됩 니 다.
import preval from 'preval.macro'
const one = 1
사용 방식 으로 볼 때 매크로 와 의 관 계 를 식별 하 는 유일한 것 은*.macro 문자 입 니 다.이것 은 바로 Babel 이 매크로 를 어떻게 식별 하 는 방식 입 니 다.실제로*.macro 의 형식 뿐만 아니 라 Babel 은 라 이브 러 리 이름 이 정규/[./]macro(\.c?js)와 일치 하 다 고 생각 합 니까?$/표현 식 의 라 이브 러 리 는 Babel 매크로 입 니 다.표현 식 과 일치 하 는 예 입 니 다.
'my.macro'
'my.macro.js'
'my.macro.cjs'
'my/macro'
'my/macro.js'
'my/macro.cjs'
집필 하 다다음은 importURL 매크로 를 간단하게 작성 할 것 입 니 다.url 을 통 해 라 이브 러 리 를 도입 하고 컴 파일 하 는 동안 이 라 이브 러 리 의 코드 를 미리 끌 어 내 서 처리 한 다음 파일 에 도입 하 는 역할 을 합 니 다.일부 웹 팩 플러그 인 은 url 에서 라 이브 러 리 를 도입 하 는 것 을 지원 한 다 는 것 을 알 고 있 습 니 다.그러나 이것 은 매크로 를 어떻게 만 드 는 지 배 우 는 좋 은 예 입 니 다.재 미 를 위해 서 입 니 다!그리고 NodeJS 에서 동기 화 요청 을 하 는 방법!:)
준비 하 다.
먼저 importURL 이라는 폴 더 를 만 들 고 npm init-y 를 실행 하여 항목 을 빠르게 만 듭 니 다.프로젝트 에 매크로 를 사용 하 는 사람 은 babel-plugin-macros 를 설치 해 야 합 니 다.마찬가지 로 매크로 를 작성 하 는 사람 도 이 플러그 인 을 설치 해 야 합 니 다.쓰기 전에 다른 라 이브 러 리 를 미리 설치 하여 매크로 를 작성 하 는 데 도움 을 주어 야 합 니 다.개발 하기 전에 미리:
예시
우리 의 목 표 는 다음 과 같은 코드 를 변환 하 는 것 이다.
import importURL from 'importurl.macros';
const React = importURL('https://unpkg.com/[email protected]/umd/react.development.js');
//
import importURL from 'importurl.macros';
const React = require('../cache/pkg1.js');
코드 importURL 함수 의 첫 번 째 인 자 를 원 격 라 이브 러 리 주소 로 분석 한 다음 컴 파일 기간 에 Get 요청 을 통 해 코드 내용 을 동기 화 합 니 다.그 다음 에 프로젝트 맨 위 폴 더 에.hache 를 기록 하고 해당 하 는 importURL 문 구 를 require(...)문 구 를 바 꿉 니 다.경 로 는 importURL 의 파일 이.cache 파일 의 상대 적 인 경 로 를 사용 하여 webpack 이 최종 포장 할 때 해당 하 는 코드 를 찾 을 수 있 도록 합 니 다.시작 하 다
최종 코드 가 어떻게 생 겼 는 지 먼저 봅 시다.
import { execSync } from 'child_process';
import findRoot from 'find-root';
import path from 'path';
import fse from 'fs-extra';
import { createMacro } from 'babel-plugin-macros';
const syncGet = (url) => {
const data = execSync(`curl -L ${url}`).toString();
if (data === '') {
throw new Error('empty data');
}
return data;
}
let count = 0;
export const genUniqueName = () => `pkg${++count}.js`;
module.exports = createMacro((ctx) => {
const {
references, //
babel: {
types: t,
}
} = ctx;
// babel ctx.state.filename
const workspacePath = findRoot(ctx.state.filename);
//
const cacheDirPath = path.join(workspacePath, '.cache');
//
const calls = references.default.map(path => path.findParent(path => path.node.type === 'CallExpression' ));
calls.forEach(nodePath => {
// astNode
if (nodePath.node.type === 'CallExpression') {
//
if (nodePath.node.arguments[0]?.type === 'StringLiteral') {
// ,
const url = nodePath.node.arguments[0].value;
// url
const codes = syncGet(url);
// ,
const pkgName = genUniqueName();
//
const cahceFilename = path.join(cacheDirPath, pkgName);
// fse , , outputFileSync
fse.outputFileSync(cahceFilename, codes);
//
const relativeFilename = path.relative(ctx.state.filename, cahceFilename);
// importURL
nodePath.replaceWith(t.stringLiteral(`require('${relativeFilename}')`))
}
}
});
});
매크로 만 들 기우 리 는 createMacro 함 수 를 통 해 매크로 를 만 듭 니 다.createMacro 는 우리 가 작성 한 함 수 를 매개 변수 로 받 아들 여 매크로 를 만 듭 니 다.그러나 실제로 우 리 는 createMacro 의 반환 시간 이 무엇 인지 에 관심 이 없습니다.왜냐하면 우리 의 코드 는 최종 적 으로 자신 이 바 뀌 기 때문에 실행 기간 에 실행 되 지 않 습 니 다.우리 가 작성 한 함수 의 첫 번 째 매개 변 수 는 Babel 이 우리 에 게 전달 한 상태 입 니 다.우 리 는 그 유형 이 무엇 인지 대충 볼 수 있 습 니 다.
function createMacro(handler: MacroHandler, options?: Options): any;
interface MacroParams {
references: { default: Babel.NodePath[] } & References;
state: Babel.PluginPass;
babel: typeof Babel;
config?: { [key: string]: any };
}
export interface PluginPass {
file: BabelFile;
key: string;
opts: PluginOptions;
cwd: string;
filename: string;
[key: string]: unknown;
}
가시 화 AST우 리 는astexplorer을 통 해 코드 를 처리 할 문법 트 리 를 관찰 할 수 있 습 니 다.다음 코드 에 대해 서 는...
import importURL from 'importurl.macros';
const React = importURL('https://unpkg.com/[email protected]/umd/react.development.js');
다음 문법 트 리 가 생 성 됩 니 다.빨간색 으로 표 시 된 문법 트 리 노드 는 바벨 이 ctx.references 를 통 해 우리 에 게 전달 되 기 때문에 우 리 는.findParent()방법 을 통 해 부모 노드 CallExpresstion 을 위로 찾 아야 arguments 속성 에서 의 인 자 를 얻 고 원 격 라 이브 러 리 의 URL 주 소 를 얻 을 수 있 습 니 다.
동기 화 요청
여기 서 어 려 운 점 은 바벨 이 비동기 변환 을 지원 하지 않 고 모든 변환 작업 이 동기 화 되 어 있 기 때문에 요청 을 할 때 도 동기 화 요청 이 어야 한 다 는 것 이다.나 는 이것 이 매우 간단 한 일이 라 고 생각 했 는데,Node 는 sync:true 와 유사 한 옵션 을 제공 할 것 이다.그러나 Node 는 다음 과 같은 이상 한 방식 을 선택 하지 않 는 한 동기 화 요청 을 지원 하지 않 습 니 다.
const syncGet = (url) => {
const data = execSync(`curl -L ${url}`).toString();
if (data === '') {
throw new Error('empty data');
}
return data;
}
마무리코드 를 받 은 후에 우 리 는 코드 를 계산 하기 시작 한 파일 경로 에 기록 합 니 다.여기 서 fs-extra 를 사용 하 는 목적 은 fs-extra 가 기록 할 때 폴 더 가 존재 하지 않 으 면 fs 처럼 오 류 를 직접 던 지지 않 고 해당 하 는 파일 을 자동 으로 만 드 는 것 입 니 다.쓰기 가 끝 난 후에 저 희 는 Babel 이 제공 하 는 보조 적 인 방법 인 string Literal 을 통 해 문자열 노드 를 만 든 다음 에 저희 importURL(...)을 교체 하면 저희 의 전체 전환 절 차 는 끝 납 니 다.
마지막.
이 매크로 는 약간의 결함 이 존재 하 므 로 관심 이 있 는 학생 들 은 계속 보완 할 수 있다.
같은 URL 의 라 이브 러 리 를 인식 하지 못 하고 재 활용 을 했 지만 매크로 를 만 드 는 방법 에 만족 했다 고 생각 합 니 다.
genUniqueName 은 크로스 파일 에서 중복 패키지 이름 을 계산 합 니 다.정확 한 알고리즘 은 url 에 따라 해시 값 을 계산 하여 유일한 패키지 이름 으로 해 야 합 니 다.
자 바스 크 립 트 에서 매크로 를 어떻게 사용 하 는 지 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자 바스 크 립 트 는 매크로 내용 을 사용 합 니 다.예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Thymeleaf 의 일반 양식 제출 과 AJAX 제출텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.