In Sprachen werden häufig Makros zur Implementierung von DSLs verwendet. Durch Makros können Entwickler das Format einiger Sprachen anpassen, beispielsweise durch Implementierung der JSX-Syntax. Da WASM nun implementiert ist, ist es nicht unmöglich, Webseiten in anderen Sprachen zu schreiben. Beispielsweise verfügt die Sprache Rust über eine leistungsstarke Makrofunktion, was bedeutet, dass das auf Rust basierende Yew-Framework nichts wie Babel implementieren muss, sondern eine JSX-ähnliche Syntax implementieren kann, indem es sich auf die Sprache selbst verlässt. Ein Beispiel für eine Yew-Komponente, die eine JSX-ähnliche Syntax unterstützt. impl Component für MyComponent { // ... fn Ansicht(&selbst) -> Html { : Lassen Sie onclick = self.link.callback(|_| Msg::Click); html! { <button beim Klicken=beim Klicken>{ self.props.button_text }</button> } } } Einschränkungen von JavaScript-MakrosIm Gegensatz zu Rust unterstützt JavaScript selbst keine Makros, daher berücksichtigt die gesamte Toolchain keine Makros. Sie können also ein Makro schreiben, das benutzerdefinierte Syntax erkennt, aber da die unterstützende Toolchain, wie etwa die gängigsten VSCode und Typescript, diese nicht unterstützt, erhalten Sie einen Syntaxfehler. Ebenso unterstützt der von Babel selbst verwendete Parser keine erweiterte Syntax, es sei denn, Sie forken ein weiteres Babel. Daher unterstützt Babel-Plugin-Macros keine benutzerdefinierte Syntax. Mithilfe von Template-String-Funktionen können wir jedoch einen Umweg machen und zumindest die Möglichkeit erlangen, den Syntaxbaum teilweise anzupassen. Ein GraphQL-Beispiel, das das direkte Schreiben von GraphQL in JavaScript unterstützt. importiere { gql } aus „graphql.macro“; const Abfrage = gql` Abfrage Benutzer { Benutzer(ID: 5) { Nachname ...Benutzereintrag1 } } `; // Wird zur Kompilierzeit in ↓ ↓ ↓ ↓ ↓ ↓ umgewandelt const Abfrage = { "Art": "Dokument", "Definitionen": [{ ... Warum Makros anstelle von Babel-Plugins verwenden?Die Fähigkeiten von Babel-Plugins sind tatsächlich viel größer als die von Makros, und in manchen Fällen müssen Sie wirklich Plugins verwenden. Ein Vorteil von Makros gegenüber Babel-Plugins besteht darin, dass die Idee von Makros darin besteht, sie sofort einsatzbereit zu verwenden. Entwickler, die React verwenden, haben sicherlich schon von der berühmten Create-React-App gehört, die verschiedene zugrunde liegende Details für Sie kapselt, sodass sich Entwickler auf das Schreiben von Code konzentrieren können. Das Problem mit CRA ist jedoch, dass es zu eng gekapselt ist. Wenn Sie das Babel-Plugin überhaupt anpassen müssen, müssen Sie im Grunde yarn react-script eject ausführen, um alle zugrunde liegenden Details offenzulegen. Was Makros betrifft, müssen Sie lediglich ein Plugin „babel-plugin-macros“ in der Babel-Konfiguration des Projekts hinzufügen. Anschließend werden alle benutzerdefinierten Babel-Makros perfekt unterstützt, anstatt verschiedene Plugins wie Plug-ins herunterladen zu müssen. CRA verfügt über integrierte Babel-Plugin-Makros, Sie können beliebige Babel-Makros in Ihrem CRA-Projekt verwenden. Wie schreibt man ein Makro? einführen Ein Makro ist einem Babel-Plugin sehr ähnlich, daher ist es sehr hilfreich, im Voraus zu wissen, wie man ein Babel-Plugin schreibt. Babel verfügt offiziell über ein Handbuch zum Schreiben eines Babel-Plugins von Grund auf. Nachdem wir nun wissen, wie man Babel-Plugins schreibt, wollen wir zunächst anhand eines Beispiels für die Verwendung von Makros erklären, wie Babel Makros in Dateien identifiziert. Handelt es sich um eine spezielle Syntax oder einfach nur um einen falschen Gebrauch des $-Symbols? importiere preval aus „preval.macro“ const one = preval `module.exports = 1 + 2 - 1 - 1` Dies ist ein sehr verbreitetes Makro. Seine Funktion besteht darin, den JavaScript-Code während der Kompilierung in der Zeichenfolge auszuführen und dann das Ausführungsergebnis durch die entsprechende Stelle zu ersetzen. Der obige Code wird wie folgt erweitert: importiere preval aus „preval.macro“ Konstante eins = 1 Aus Sicht der Nutzung ist das einzige, was mit der Identifizierung von Makros zusammenhängt, das Zeichen *.macro, und das ist tatsächlich die Art und Weise, wie Babel Makros identifiziert. Tatsächlich betrachtet Babel nicht nur für die Form *.macro Bibliotheken, deren Namen dem regulären Ausdruck /[./]macro(\.c?js)?$/ entsprechen, als Babel-Makros. Einige Beispiele für diese übereinstimmenden Ausdrücke: „mein.Makro“ „mein.macro.js“ „mein.macro.cjs“ 'mein/Makro' „mein/macro.js“ „mein/macro.cjs“ schreibenAls Nächstes schreiben wir einfach ein ImportURL-Makro, mit dem einige Bibliotheken über URLs importiert werden. Der Code dieser Bibliotheken wird während der Kompilierung vorab abgerufen, verarbeitet und dann in die Datei importiert. Ich weiß, dass einige Webpack-Plugins bereits das Importieren von Bibliotheken aus URLs unterstützen, aber dies ist auch ein gutes Beispiel, um das Schreiben von Makros zu lernen, einfach nur zum Spaß! Und wie man synchrone Anfragen in NodeJS macht! :) Vorbereiten Erstellen Sie zunächst einen Ordner mit dem Namen „importURL“ und führen Sie „npm init -y“ aus, um schnell ein Projekt zu erstellen. Personen, die Makros im Projekt verwenden, müssen babel-plugin-macros installieren. Ebenso müssen diejenigen, die Makros schreiben, dieses Plug-In installieren. Vor dem Schreiben müssen wir auch einige andere Bibliotheken installieren, die uns beim Schreiben von Makros unterstützen. Vor der Entwicklung müssen wir:
Beispiel Unser Ziel ist es, den folgenden Code umzuwandeln in importiere Import-URL aus „importurl.macros“; const React = importURL('https://unpkg.com/[email protected]/umd/react.development.js'); // Kompilieren, um importURL aus „importurl.macros“ zu importieren; const React = require('../cache/pkg1.js'); Wir analysieren den ersten Parameter der ImportURL-Funktion des Codes als Adresse der Remote-Bibliothek und ziehen dann den Codeinhalt während der Kompilierung synchron über die Get-Anforderung ab. Schreiben Sie es dann in die .cache-Datei im obersten Ordner des Projekts und ersetzen Sie die entsprechende importURL-Anweisung durch eine require(...)-Anweisung. Der Pfad... verwendet den relativen Pfad in der .cache-Datei der importURL-Datei, damit Webpack den entsprechenden Code finden kann, wenn er endgültig gepackt ist. Start Schauen wir uns zunächst an, wie der endgültige Code aussieht importiere { execSync } von „Unterprozess“; importiere findRoot von „find-root“; Pfad von „Pfad“ importieren; importiere fse von „fs-extra“; importiere { createMacro} aus „babel-plugin-macros“; const syncGet = (url) => { const data = execSync(`curl -L ${url}`).toString(); wenn (Daten === '') { wirf einen neuen Fehler (,leere Daten‘); } Daten zurückgeben; } lass count = 0; export const genUniqueName = () => `pkg${++count}.js`; modul.exports = erstelleMakro((ctx) => { Konstante { Referenzen, // Alle Referenzen auf Makros in der Datei babel: { typen: t, } } = ctx; // Babel setzt den aktuell verarbeiteten Dateipfad auf ctx.state.filename const workspacePath = findRoot(ctx.state.filename); // Cache-Ordner berechnen const cacheDirPath = path.join(workspacePath, '.cache'); // const calls = references.default.map(Pfad => Pfad.findParent(Pfad => Pfad.node.type === 'CallExpression' )); Aufrufe.fürJeden(nodePath => { // Bestimme den Typ von astNode, wenn (nodePath.node.type === 'CallExpression') { // Stellen Sie sicher, dass das erste Argument der Funktion ein reiner String ist, if (nodePath.node.arguments[0]?.type === 'StringLiteral') { // Einen Parameter als Adresse der Remote-Bibliothek abrufen const url = nodePath.node.arguments[0].value; // Codes entsprechend der URL abrufen const codes = syncGet(url); // Generieren Sie einen eindeutigen Paketnamen, um Konflikte zu vermeiden const pkgName = genUniqueName(); // Bestimmen Sie den endgültigen Dateipfad, der geschrieben werden soll const cahceFilename = path.join(cacheDirPath, pkgName); //Schreibe den Inhalt über die fse-Bibliothek, outputFileSync erstellt automatisch einen nicht vorhandenen Ordner fse.outputFileSync(cahceFilename, codes); // Den relativen Pfad berechnen const relativeFilename = path.relative(ctx.state.filename, cahceFilename); // Endgültige Berechnung zum Ersetzen der importURL-Anweisung nodePath.replaceWith(t.stringLiteral(`require('${relativeFilename}')`)) } } }); }); Erstellen eines Makros Wir erstellen ein Makro über die Funktion createMacro. createMacro akzeptiert die von uns geschriebene Funktion als Parameter, um ein Makro zu generieren, aber der Rückgabewert von createMacro ist uns eigentlich egal, da unser Code letztendlich durch sich selbst ersetzt wird und zur Laufzeit nicht ausgeführt wird. Das erste Argument der von uns geschriebenen Funktion ist ein Zustand, den Babel an uns übergeben hat, und wir können kurz nachsehen, um welchen Typ es sich handelt. Funktion createMacro(Handler: MacroHandler, Optionen?: Optionen): beliebig; Schnittstelle MacroParams { Referenzen: { Standard: Babel.NodePath[] } & Referenzen; Status: Babel.PluginPass; babel: Typ von Babel; Konfiguration?: { [Schlüssel: Zeichenfolge]: beliebig }; } Exportschnittstelle PluginPass { Datei: BabelFile; Schlüssel: Zeichenfolge; opts: Plugin-Optionen; cwd: Zeichenfolge; Dateiname: Zeichenfolge; [Schlüssel: Zeichenfolge]: unbekannt; } Visualisierung des AST Wir können astexplorer verwenden, um den Syntaxbaum des Codes zu beobachten, den wir verarbeiten werden. Für den folgenden Code importiere Import-URL aus „importurl.macros“; const React = importURL('https://unpkg.com/[email protected]/umd/react.development.js'); Der folgende Syntaxbaum wird generiert Die rot markierten Syntaxbaumknoten sind das, was Babel uns über ctx.references übergibt. Daher müssen wir die Methode .findParent() verwenden, um den übergeordneten Knoten CallExpression zu finden, um die Parameter unter der Argumenteigenschaft abzurufen und die URL-Adresse der Remote-Bibliothek zu erhalten. Synchrone Anfrage Eine Schwierigkeit besteht hier darin, dass Babel keine asynchronen Transformationen unterstützt. Alle Transformationsvorgänge sind synchron, daher muss die Anfrage auch eine synchrone Anfrage sein. Ich hätte gedacht, dass das ganz einfach wäre und Node eine Option wie „sync: true“ bereitstellen würde. Aber nein, Node unterstützt keine synchronen Anfragen, es sei denn, Sie entscheiden sich für die folgende seltsame Art und Weise const syncGet = (url) => { const data = execSync(`curl -L ${url}`).toString(); wenn (Daten === '') { wirf einen neuen Fehler (,leere Daten‘); } Daten zurückgeben; } Ende Nachdem wir den Code erhalten haben, schreiben wir ihn in den zu Beginn berechneten Dateipfad. Der Zweck der Verwendung von fs-extra besteht hier darin, dass fs-extra, wenn es beim Schreiben auf einen nicht vorhandenen Ordner stößt, nicht direkt wie fs einen Fehler auslöst, sondern automatisch die entsprechende Datei erstellt. Nachdem der Schreibvorgang abgeschlossen ist, erstellen wir einen Zeichenfolgenknoten mithilfe der von Babel bereitgestellten Hilfsmethode stringLiteral, ersetzen dann unsere importURL(...) und unser gesamter Konvertierungsprozess ist abgeschlossen. endlichDieses Makro weist einige Mängel auf und interessierte Studierende können es weiter verbessern: Es gibt keine Bibliothek zum Identifizieren und Wiederverwenden derselben URL, aber ich denke, diese reichen zum Schreiben eines Makros aus. genUniqueName berechnet doppelte Paketnamen in allen Dateien. Der richtige Algorithmus sollte darin bestehen, den Hashwert basierend auf der URL als eindeutigen Paketnamen zu berechnen. Dies ist das Ende dieses Artikels über die Verwendung von Makros in JavaScript. Weitere Informationen zur Verwendung von Makros in JavaScript finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen! Das könnte Sie auch interessieren:
|
<<: MySQL 5.7.20 Zip-Installations-Tutorial
>>: So aktivieren Sie Flash in Windows Server 2016
HTML-img-Tag: definiert ein Bild, das in eine Webs...
Heute werden wir einen einfachen Herzschlageffekt...
1. Herunterladen https://dev.mysql.com/downloads/...
Ziehen Sie das Bild # Docker-Pull Codercom/Code-S...
In diesem Artikel wird der spezifische Code für d...
Bei der Optimierung einer Website müssen wir lern...
Beim Speichern von Daten in MySQL werden manchmal...
Rational ClearCase ist ein Tool für das Softwarek...
Ein Satz zur Einführung von HOC Was ist eine Komp...
Vor kurzem hat ein Dienst einen Alarm ausgelöst, ...
Vorwort Im Falle eines Anwendungsfehlers oder ein...
Der Code sieht folgendermaßen aus: SELECT @i:=@i+...
Vorwort Jeder sollte mit der Watch-API in vue2 ve...
XML Schema ist eine XML-basierte Alternative zu D...
Vorwort smb ist der Name eines Protokolls, das fü...