Wie kopiere ich statische Dateien, um ein Verzeichnis mit Webpack zu erstellen?

330

Ich versuche , von sich zu bewegen Gulpzu Webpack. In GulpIch habe eine Aufgabe, die alle Dateien und Ordner von / static / Ordner nach / build / Ordner kopiert . Wie mache ich das gleiche mit Webpack? Benötige ich ein Plugin?

Vitalii Korsakov
quelle
2
Gulp ist toll zu verstehen. Rufen Sie einfach das Webpack von gulpfile.js an, wenn Sie möchten
Baryon Lee
Wenn Sie Laravel Mix verwenden, ist laravel.com/docs/5.8/mix#copying-files-and-directories verfügbar.
Ryan

Antworten:

179

Sie müssen keine Dinge kopieren, das Webpack funktioniert anders als das Schlucken. Webpack ist ein Modulbündler und alles, was Sie in Ihren Dateien referenzieren, wird eingeschlossen. Sie müssen nur einen Loader dafür angeben.

Also, wenn Sie schreiben:

var myImage = require("./static/myImage.jpg");

Webpack versucht zunächst, die referenzierte Datei als JavaScript zu analysieren (da dies die Standardeinstellung ist). Das wird natürlich scheitern. Aus diesem Grund müssen Sie einen Loader für diesen Dateityp angeben. Die Datei - oder beispielsweise der URL-Loader - nimmt die referenzierte Datei, legt sie im Ausgabeordner des Webpacks ab (was buildin Ihrem Fall der Fall sein sollte) und gibt die Hash-URL für diese Datei zurück.

var myImage = require("./static/myImage.jpg");
console.log(myImage); // '/build/12as7f9asfasgasg.jpg'

Normalerweise werden Lader über die Webpack-Konfiguration angewendet:

// webpack.config.js

module.exports = {
    ...
    module: {
        loaders: [
            { test: /\.(jpe?g|gif|png|svg|woff|ttf|wav|mp3)$/, loader: "file" }
        ]
    }
};

Natürlich müssen Sie zuerst den File-Loader installieren, damit dies funktioniert.

Johannes Ewald
quelle
42
" Natürlich müssen Sie zuerst den File-Loader installieren, damit dies funktioniert. " Link zum oben genannten "File-Loader" hier . Und hier erfahren Sie, wie Sie es installieren und verwenden.
Nate
21
Sie haben immer noch das Problem, dass HTML-Dateien und alle darin enthaltenen Referenzen nicht geladen werden.
Kilianc
125
Ja, wenn Sie in die Hölle der Webpack-Plugins eintauchen möchten, können Sie File-Loader, CSS-Loader, Style-Loader, URL-Loader usw. verwenden, und dann können Sie es großartig konfigurieren, wie Sie es benötigen und googeln und nicht schlafen :) oder Sie können das Copy-Webpack-Plugin verwenden und Ihre Arbeit erledigen ...
Kamil Tomšík
11
@ KamilTomšík Sie empfehlen also, ein Webpack-Plugin zu verwenden, um Webpack-Plugins zu vermeiden? (Nur ein Scherz. Ich habe verstanden.)
Konrad Viltersten
12
Ok, die meisten Bilder sind in CSS und HTML. Sollte ich also alle diese Bilder in meinen JS-Dateien mit require ('img.png') benötigen? damit es mit diesem File-Loader funktioniert? Das ist ziemlich verrückt.
Rantiev
579

Das Erfordernis von Assets mithilfe des File-Loader-Moduls ist die Art und Weise, wie Webpack verwendet werden soll ( Quelle ). Wenn Sie jedoch mehr Flexibilität benötigen oder eine übersichtlichere Benutzeroberfläche wünschen, können Sie statische Dateien auch direkt mit my copy-webpack-plugin( npm , Github ) kopieren . Für die staticzum buildBeispiel:

const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
    context: path.join(__dirname, 'your-app'),
    plugins: [
        new CopyWebpackPlugin([
            { from: 'static' }
        ])
    ]
};
kevlened
quelle
11
Dies ist viel einfacher, wenn Sie ein ganzes Verzeichnis kopieren möchten (z. B. statisches HTML und andere Boilerplate-Bilder)!
Arjun Mehta
6
Hat den Trick gemacht, danke :) hat den File Loader nach mehreren fehlgeschlagenen Versuchen aufgegeben, einen sehr einfachen Befehl auszuführen. Ihr Plugin hat beim ersten Mal funktioniert.
Arcseldon
3
@Yan Das Plugin kopiert Dateien erneut, wenn sie sich ändern (Dev-Server oder Webpack --watch). Wenn es nicht für Sie kopiert wird, reichen Sie bitte ein Problem ein.
Kevlened
2
Ich bin neu in Webpack, aber es fällt mir schwer zu verstehen, warum wir File-Loader / URL-Loader / Img-Loader verwenden müssen ... anstatt sie nur zu kopieren? Was ist der Vorteil, den wir daraus ziehen, wenn wir beispielsweise einen Dateilader verwenden?
BreakDS
2
Da bist du der Plugin-Autor. Es gibt kein besseres Tempo, um diese Frage zu stellen. Mit dem Plugin "copy-webpack-plugin" kann ich die Dateien aus dem Quellverzeichnis so filtern, dass sie nur mit einer bestimmten Dateierweiterung kopiert werden. nur ".html" kopieren? Grüße
DevWL
56

Wenn Sie Ihre statischen Dateien kopieren möchten, können Sie den File-Loader folgendermaßen verwenden:

für HTML-Dateien:

in webpack.config.js:

module.exports = {
    ...
    module: {
        loaders: [
            { test: /\.(html)$/,
              loader: "file?name=[path][name].[ext]&context=./app/static"
            }
        ]
    }
};

in Ihrer js-Datei:

  require.context("./static/", true, /^\.\/.*\.html/);

./static/ ist relativ zu dem Ort, an dem sich Ihre js-Datei befindet.

Sie können das gleiche mit Bildern oder was auch immer tun. Der Kontext ist eine mächtige Methode zum Erkunden !!

Moussa Dembélé
quelle
3
Ich bevorzuge diese Methode gegenüber dem Copy-Webpack-Plugin-Modul. Außerdem konnte ich es zum Laufen bringen, ohne "& context =. / App / static" in meiner Webpack-Konfiguration zu verwenden. Ich brauchte nur die Zeile require.context.
Dave Landry
2
Ich versuche es, es scheint großartig, aber für ein kleines Problem, das ich bekomme, ist es, dass es mein index.htmlin ein Unterverzeichnis legt, das es erstellt, genannt _(Unterstrich). Was ist los?
Kris
2
Wenn Sie "in Ihrer JS-Datei" sagen, was meinen Sie damit? Was ist, wenn ich keine JS-Datei habe?
Evolutionxbox
absolut. Diese eine Zeile im main.jsstaticrequire.context("./static/", true, /^.*/);
Mario
2
Dies ist ein ordentlicher Hack, aber wenn Sie zu viele Dateien kopieren, geht Ihnen der Speicher aus.
Tom
18

Ein Vorteil, den das oben erwähnte Copy-Webpack-Plugin bringt, der zuvor noch nicht erklärt wurde, besteht darin, dass alle anderen hier genannten Methoden die Ressourcen weiterhin in Ihren Bundle-Dateien bündeln (und erfordern, dass Sie sie irgendwo "benötigen" oder "importieren"). Wenn ich nur einige Bilder oder Teilvorlagen verschieben möchte, möchte ich meine Javascript-Bundle-Datei nicht mit nutzlosen Verweisen auf sie überladen, sondern nur, dass die Dateien an der richtigen Stelle ausgegeben werden. Ich habe im Webpack keinen anderen Weg gefunden, dies zu tun. Zugegeben, es ist nicht das, wofür Webpack ursprünglich entwickelt wurde, aber es ist definitiv ein aktueller Anwendungsfall. (@BreakDS Ich hoffe, dies beantwortet Ihre Frage - es ist nur ein Vorteil, wenn Sie es wollen)

steev
quelle
7

Die obigen Vorschläge sind gut. Aber um zu versuchen, Ihre Frage direkt zu beantworten, würde ich vorschlagen, cpy-cliin einem Skript zu verwenden, das in Ihrem definiert ist package.json.

Dieses Beispiel erwartet nodeirgendwo auf Ihrem Weg. cpy-cliAls Entwicklungsabhängigkeit installieren :

npm install --save-dev cpy-cli

Erstellen Sie dann einige NodeJS-Dateien. Einer zum Kopieren und der andere zum Anzeigen eines Häkchens und einer Meldung.

copy.js

#!/usr/bin/env node

var shelljs = require('shelljs');
var addCheckMark = require('./helpers/checkmark');
var path = require('path');

var cpy = path.join(__dirname, '../node_modules/cpy-cli/cli.js');

shelljs.exec(cpy + ' /static/* /build/', addCheckMark.bind(null, callback));

function callback() {
  process.stdout.write(' Copied /static/* to the /build/ directory\n\n');
}

checkmark.js

var chalk = require('chalk');

/**
 * Adds mark check symbol
 */
function addCheckMark(callback) {
  process.stdout.write(chalk.green(' ✓'));
  callback();
}

module.exports = addCheckMark;

Fügen Sie das Skript hinzu package.json. Vorausgesetzt, Skripte sind in<project-root>/scripts/

...
"scripts": {
  "copy": "node scripts/copy.js",
...

So führen Sie den sript aus:

npm run copy

RnR
quelle
3
OP wollte die Datei innerhalb des Webpacks verschieben, ohne npm-Skripte zu verwenden?
William S
Selbst wenn OP dieses Problem im Webpack lösen wollte, ist es möglich, dass er das Webpack über npm ausführt, sodass er es seinem Build-Skript hinzufügen kann, in dem das Webpack ausgeführt wird
Piro sagt Reinstate Monica
5

Höchstwahrscheinlich sollten Sie CopyWebpackPlugin verwenden, das in kevlened answer erwähnt wurde. Alternativ können Sie für einige Arten von Dateien wie .html oder .json auch Raw-Loader oder Json-Loader verwenden. Installieren Sie es über npm install -D raw-loaderund dann müssen Sie nur noch einen weiteren Loader zu unserer webpack.config.jsDatei hinzufügen .

Mögen:

{
    test: /\.html/,
    loader: 'raw'
}

Hinweis: Starten Sie den Webpack-Dev-Server neu, damit alle Konfigurationsänderungen wirksam werden.

Und jetzt können Sie HTML-Dateien mit relativen Pfaden anfordern. Dies erleichtert das Verschieben von Ordnern erheblich.

template: require('./nav.html')  
Andurit
quelle
5

Die Art imagesund Weise, wie ich statisch lade und fonts:

module: {
    rules: [
      ....

      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        /* Exclude fonts while working with images, e.g. .svg can be both image or font. */
        exclude: path.resolve(__dirname, '../src/assets/fonts'),
        use: [{
          loader: 'file-loader',
          options: {
            name: '[name].[ext]',
            outputPath: 'images/'
          }
        }]
      },
      {
        test: /\.(woff(2)?|ttf|eot|svg|otf)(\?v=\d+\.\d+\.\d+)?$/,
        /* Exclude images while working with fonts, e.g. .svg can be both image or font. */
        exclude: path.resolve(__dirname, '../src/assets/images'),
        use: [{
          loader: 'file-loader',
          options: {
            name: '[name].[ext]',
            outputPath: 'fonts/'
          },
        }
    ]
}

Vergessen Sie nicht zu installieren file-loader, damit das funktioniert.

RegarBoy
quelle
Wie gehen Sie mit doppelten Dateinamen um? Oder noch besser, Sie kennen eine Möglichkeit, den ursprünglichen Pfad im neuen Ausgabeverzeichnis beizubehalten?
Cantuket
Sie sollten in Ihrem Projekt keinen doppelten Dateinamen mit demselben Erweiterungsnamen haben. Was nützt es, Duplikate aufzubewahren, wenn deren Inhalt identisch ist? Wenn nicht, benennen Sie sie je nach Inhalt unterschiedlich. Aber warum sollten Sie Webpack verwenden, wenn Sie Ihre Sachen auf dem ursprünglichen Weg halten möchten? Wenn Sie nur eine JS-Übersetzung wünschen, sollte Babel ausreichen.
RegarBoy
1
Wenn Sie eine komponentenbasierte Entwicklung implementieren (eines der Hauptprinzipien ist die Kapselung und insbesondere das Verstecken von Informationen in diesem Fall ) , ist nichts von dem, was Sie erwähnt haben, relevant. Das heißt, wenn jemand dem Programm eine neue Komponente hinzufügt, sollte er weder prüfen müssen, ob ein anderes Bild benannt ist, logo.pngnoch einen stumpfen und "hoffentlich" eindeutigen Dateinamen erstellen müssen, um eine globale Kollision zu vermeiden. Aus demselben Grund verwenden wir CSS-Module .
Cantuket
1
Warum möchte ich, dass Bilder den ursprünglichen Pfad und Dateinamen beibehalten? Debuggen meistens aus demselben Grund, aus dem Sie Sourcemaps verwenden würden, aber auch SEO . Unabhängig davon war die Antwort auf meine Frage eigentlich sehr einfach ... [path][name].[ext]und es gibt viel Flexibilität, um dies für eine bestimmte Umgebung oder einen bestimmten Anwendungsfall zu ändern ... File-Loader
Cantuket
1
Davon abgesehen haben wir eine Variation Ihres Beispiels implementiert. Vielen Dank für Ihre Bereitstellung!
Cantuket
3

Sie können bash in Ihr package.json schreiben:

# package.json
{
  "name": ...,
  "version": ...,
  "scripts": {
    "build": "NODE_ENV=production npm run webpack && cp -v <this> <that> && echo ok",
    ...
  }
}
Victor Pudeyev
quelle
1
Verwenden Sie unter Windows einfach xcopy anstelle von cp:"build": "webpack && xcopy images dist\\images\\ /S /Y && xcopy css dist\\css\\ /S /Y"
SebaGra
7
Richtig, Ihre Lösung besteht also darin, für jedes Betriebssystem ein anderes Skript zu haben?
Maciej Gurban
Ja, für mich ist ein Skript für jedes Betriebssystem akzeptabel (es ist wirklich Unix / Nicht-Unix, da ein Skript unter Linux unter Darwin oder einem anderen POSIX * nix ausgeführt wird)
Victor Pudeyev
Und dieses Windows-Beispiel funktioniert auch nicht mit PowerShell als Standard-Shell.
Julian Knight
Im Gegensatz zu CopyWebpackPlugin werden bei dieser Option Dateidaten beibehalten. Das Betriebssystemproblem kann für Open Source problematisch sein, aber für kleinere Teams kann es problemlos mit Windows Bash oder dem Umschließen von xcopy mit cp.bat verwaltet werden.
Alien Technology
2

Ich war auch hier fest. Copy-Webpack-Plugin hat bei mir funktioniert.

Allerdings war 'Copy-Webpack-Plugin' in meinem Fall nicht notwendig (ich habe es später erfahren).

Das Webpack ignoriert das
Beispiel für Root-Pfade

<img src="/images/logo.png'>

Damit dies funktioniert, ohne das 'Copy-Webpack-Plugin' zu verwenden, verwenden Sie '~' in Pfaden

<img src="~images/logo.png'>

'~' weist das Webpack an, 'images' als Modul zu betrachten

Hinweis: Möglicherweise müssen Sie das übergeordnete Verzeichnis des Bilderverzeichnisses hinzufügen

resolve: {
    modules: [
        'parent-directory of images',
        'node_modules'
    ]
}

Besuchen Sie https://vuejs-templates.github.io/webpack/static.html

techNik
quelle
2

Mit der Webpack-Konfigurationsdatei (in Webpack 2) können Sie eine Versprechenskette exportieren, solange der letzte Schritt ein Webpack-Konfigurationsobjekt zurückgibt. Siehe Konfigurationsdokumente für Versprechen . Von dort:

Das Webpack unterstützt jetzt die Rückgabe eines Versprechens aus der Konfigurationsdatei. Dies ermöglicht die asynchrone Verarbeitung in Ihrer Konfigurationsdatei.

Sie können eine einfache rekursive Kopierfunktion erstellen, die Ihre Datei kopiert und erst danach das Webpack auslöst. Z.B:

module.exports = function(){
    return copyTheFiles( inpath, outpath).then( result => {
        return { entry: "..." } // Etc etc
    } )
}
Mentor
quelle
1

Nehmen wir an, alle Ihre statischen Assets befinden sich in einem Ordner "statisch" auf der Stammebene und Sie möchten sie in den Build-Ordner kopieren, wobei die Struktur des Unterordners beibehalten wird, und dann einfach in Ihre Eingabedatei einfügen

//index.js or index.jsx

require.context("!!file?name=[path][name].[ext]&context=./static!../static/", true, /^\.\/.*\.*/);
abhisekpaul
quelle