Comment copier des fichiers statiques pour créer un répertoire avec Webpack?

331

J'essaie de passer de Gulpà Webpack. Dans GulpJ'ai une tâche qui copie tous les fichiers et dossiers du dossier / static / vers le dossier / build / . Comment faire de même avec Webpack? Ai-je besoin d'un plugin?

Vitalii Korsakov
la source
2
Gulp est super à comprendre. appelez simplement webpack depuis gulpfile.js si vous voulez
Baryon Lee
Si vous utilisez Laravel Mix, laravel.com/docs/5.8/mix#copying-files-and-directories est disponible.
Ryan

Réponses:

179

Vous n'avez pas besoin de copier les choses, le webpack fonctionne différemment de gulp. Webpack est un module de regroupement et tout ce que vous référencez dans vos fichiers sera inclus. Il vous suffit de spécifier un chargeur pour cela.

Donc, si vous écrivez:

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

Webpack essaiera d'abord d'analyser le fichier référencé en JavaScript (car c'est la valeur par défaut). Bien sûr, cela échouera. C'est pourquoi vous devez spécifier un chargeur pour ce type de fichier. Le fichier - ou le chargeur d' url, par exemple, prend le fichier référencé, le place dans le dossier de sortie de webpack (qui devrait être builddans votre cas) et renvoie l'url hachée pour ce fichier.

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

Les chargeurs sont généralement appliqués via la configuration du webpack:

// webpack.config.js

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

Bien sûr, vous devez d'abord installer le chargeur de fichiers pour que cela fonctionne.

Johannes Ewald
la source
42
" Bien sûr, vous devez d'abord installer le chargeur de fichiers pour que cela fonctionne. " Lien vers le "chargeur de fichiers" susmentionné ici . Et voici comment l'installer et l'utiliser.
Nate
21
Vous avez toujours le problème des fichiers HTML et toutes les références qu'ils contiennent ne sont pas chargées.
kilianc
126
oui, si vous voulez entrer dans l'enfer des plugins webpack, vous pouvez utiliser le chargeur de fichiers, le chargeur css, le chargeur de style, le chargeur d'url, ... et ensuite vous pouvez passer un bon moment à le configurer comme vous le souhaitez et googler et ne pas dormir :) ou vous pouvez utiliser le plugin copy-webpack et faire votre travail ...
Kamil Tomšík
11
@ KamilTomšík Donc, votre recommandation est que nous devrions utiliser un plugin webpack pour éviter les plugins webpack? (Je plaisante. J'ai compris.)
Konrad Viltersten
12
Ok, la plupart de toutes les images sont en CSS et en HTML. Dois-je donc exiger toutes ces images dans mes fichiers JS en utilisant require ('img.png'); pour le faire fonctionner avec ce chargeur de fichiers? C'est assez fou.
Rantiev
581

Exiger des ressources à l'aide du module de chargement de fichiers est la façon dont le webpack est destiné à être utilisé ( source ). Cependant, si vous avez besoin d'une plus grande flexibilité ou souhaitez une interface plus propre, vous pouvez également copier des fichiers statiques directement à l'aide de my copy-webpack-plugin( npm , Github ). Pour staticd' buildexemple:

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

module.exports = {
    context: path.join(__dirname, 'your-app'),
    plugins: [
        new CopyWebpackPlugin([
            { from: 'static' }
        ])
    ]
};
kevlened
la source
11
C'est tellement plus simple quand vous voulez copier un répertoire entier (ie. Html statique et autres images passe-partout)!
Arjun Mehta
6
Vous avez fait l'affaire, merci :) a abandonné le chargeur de fichiers après plusieurs tentatives infructueuses pour obtenir une commande très simple. votre plugin a fonctionné la première fois.
arcseldon
3
@Yan Le plugin recopie les fichiers s'ils changent (dev-server ou webpack --watch). S'il ne copie pas pour vous, veuillez signaler un problème.
kevlened
2
Je suis nouveau sur webpack, mais j'ai du mal à comprendre pourquoi nous devons utiliser le chargeur de fichiers / chargeur d'url / chargeur d'img ... au lieu de simplement les copier? Quel est l'avantage que nous retirons de cette opération avec, par exemple, le chargeur de fichiers?
BreakDS
2
Puisque vous êtes l'auteur du plugin. Il n'y a pas de meilleur rythme pour poser cette question. En utilisant le plugin "copy-webpack-plugin" ... puis-je filtrer les fichiers du répertoire source afin qu'il ne copie que le fichier avec une certaine extension de fichier ex. copier uniquement ".html"? Cordialement
DevWL
56

Si vous souhaitez copier vos fichiers statiques, vous pouvez utiliser le chargeur de fichiers de cette manière:

pour les fichiers html:

dans webpack.config.js:

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

dans votre fichier js:

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

./static/ est relatif à l'emplacement de votre fichier js.

Vous pouvez faire de même avec des images ou autre chose. Le contexte est une méthode puissante à explorer !!

Moussa Dembélé
la source
3
Je préfère cette méthode au module copy-webpack-plugin. De plus, j'ai pu le faire fonctionner sans utiliser "& context =. / App / static" dans ma configuration webpack. Je n'avais besoin que de la ligne require.context.
Dave Landry
2
J'essaie cela, cela semble génial, mais pour un petit problème que je reçois, c'est qu'il met mon index.htmldans un sous-répertoire qu'il crée appelé _(souligné), que se passe-t-il?
kris
2
Quand vous dites "dans votre fichier js" que voulez-vous dire? Et si je n'ai pas de fichier JS?
evolutionxbox
absolument. Cette seule ligne dans le script d'entrée, c'est-à main.js- dire importe tout dans le staticdossier:require.context("./static/", true, /^.*/);
Mario
2
Il s'agit d'un hack soigné, mais si vous copiez trop de fichiers, vous manquerez de mémoire.
Tom
18

Un avantage que le plugin copy-webpack-plugin susmentionné apporte qui n'a pas été expliqué auparavant est que toutes les autres méthodes mentionnées ici regroupent toujours les ressources dans vos fichiers de bundle (et vous obligent à "exiger" ou "importer" quelque part). Si je veux simplement déplacer des images ou des modèles partiels, je ne veux pas encombrer mon fichier de bundle javascript avec des références inutiles, je veux juste que les fichiers soient émis au bon endroit. Je n'ai trouvé aucun autre moyen de le faire dans webpack. Certes, ce n'est pas pour cela que le webpack a été conçu à l'origine, mais c'est certainement un cas d'utilisation actuel. (@BreakDS J'espère que cela répond à votre question - ce n'est qu'un avantage si vous le souhaitez)

steev
la source
7

Les suggestions ci-dessus sont bonnes. Mais pour essayer de répondre directement à votre question, je suggère d'utiliser cpy-cliun script défini dans votre package.json.

Cet exemple s'attend nodeà quelque part sur votre chemin. Installer en cpy-clitant que dépendance de développement:

npm install --save-dev cpy-cli

Créez ensuite quelques fichiers nodejs. L'un pour faire la copie et l'autre pour afficher une coche et un message.

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;

Ajoutez le script package.json. En supposant que les scripts sont dans<project-root>/scripts/

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

Pour exécuter le script:

npm run copy

RnR
la source
3
OP voulait accomplir le déplacement du fichier à l'intérieur du webpack, sans utiliser de scripts npm?
William S
Même lorsque OP voulait résoudre ce problème à l'intérieur du webpack, il est possible qu'il exécute webpack via npm, donc il pourrait l'ajouter à son script de construction où webpack est exécuté
Piro dit Reinstate Monica
5

Vous devriez probablement utiliser CopyWebpackPlugin qui a été mentionné dans la réponse kevlened. Alternativement pour certains types de fichiers comme .html ou .json, vous pouvez également utiliser raw-loader ou json-loader. Installez-le via npm install -D raw-loaderet ce que vous n'avez qu'à faire est d'ajouter un autre chargeur à notre webpack.config.jsfichier.

Comme:

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

Remarque: redémarrez le webpack-dev-server pour que les modifications de configuration prennent effet.

Et maintenant, vous pouvez exiger des fichiers html en utilisant des chemins relatifs, ce qui facilite beaucoup le déplacement des dossiers.

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

La façon dont je charge statique imageset 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/'
          },
        }
    ]
}

N'oubliez pas d'installer file-loaderpour que cela fonctionne.

RegarBoy
la source
Comment gérez-vous les noms de fichiers en double? Ou mieux encore, vous connaissez un moyen de conserver le chemin d'origine dans le nouveau répertoire de sortie?
cantuket
Vous ne devriez pas avoir de nom de fichier en double avec le même nom d'extension dans votre projet. Quel est l'intérêt de conserver les doublons si leur contenu est identique? Sinon, nommez-les différemment en fonction de leur contenu. Mais pourquoi utiliseriez-vous Webpack si vous souhaitez conserver vos objets dans le chemin d'origine? Si vous ne voulez que la traduction JS, Babel devrait suffire.
RegarBoy
1
Si vous implémentez un développement basé sur les composants (dont l'un des principes principaux est l'encapsulation et plus précisément dans ce cas , le masquage des informations ) , rien de ce que vous avez mentionné n'est pertinent. Par exemple, lorsque quelqu'un ajoute un nouveau composant au programme, il ne devrait pas avoir besoin de vérifier s'il y a une autre image nommée logo.pngni de créer un nom de fichier obtus et "si tout va bien" unique pour éviter une collision globale. Même raison pour laquelle nous utilisons des modules CSS .
cantuket
1
Quant à savoir pourquoi je veux que les images conservent le chemin et le nom de fichier d'origine; débogage principalement, même raison pour laquelle vous utiliseriez des sourcemaps, mais aussi du référencement . Quoi qu'il en soit, la réponse à ma question était en fait très simple ... [path][name].[ext]et il y a beaucoup de flexibilité pour le modifier pour un environnement spécifique ou un cas d'utilisation ... file-loader
cantuket
1
Cela étant dit, nous avons mis en œuvre une variante de votre exemple, alors merci de nous avoir fourni!
cantuket
3

Vous pouvez écrire bash dans votre package.json:

# package.json
{
  "name": ...,
  "version": ...,
  "scripts": {
    "build": "NODE_ENV=production npm run webpack && cp -v <this> <that> && echo ok",
    ...
  }
}
Victor Pudeyev
la source
1
Sous Windows, utilisez simplement xcopy au lieu de cp:"build": "webpack && xcopy images dist\\images\\ /S /Y && xcopy css dist\\css\\ /S /Y"
SebaGra
7
N'est-ce pas, votre solution consiste à avoir un script différent pour chaque système d'exploitation?
Maciej Gurban
Oui, pour moi, un script pour chaque système d'exploitation est acceptable (c'est vraiment unix / non-unix, car un script sur linux s'exécutera sur Darwin ou un autre POSIX * nix)
Victor Pudeyev
Et cet exemple Windows ne fonctionnera pas non plus avec PowerShell comme shell par défaut.
Julian Knight
Contrairement à CopyWebpackPlugin, cette option conserve les dates des fichiers. Le problème du système d'exploitation peut être problématique pour l'open source, mais pour les petites équipes est facilement géré avec Windows bash ou en enveloppant xcopy avec cp.bat.
Alien Technology
2

J'étais coincé ici aussi. copy-webpack-plugin a fonctionné pour moi.

Cependant, 'copy-webpack-plugin' n'était pas nécessaire dans mon cas (j'ai appris plus tard).

webpack ignore l'
exemple des chemins racine

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

Par conséquent, pour que cela fonctionne sans utiliser 'copy-webpack-plugin', utilisez '~' dans les chemins

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

'~' demande à webpack de considérer les 'images' comme un module

remarque: vous devrez peut-être ajouter le répertoire parent du répertoire images dans

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

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

techNik
la source
2

Le fichier de configuration webpack (dans webpack 2) vous permet d'exporter une chaîne de promesses, tant que la dernière étape renvoie un objet de configuration webpack. Voir les documents de configuration des promesses . De là:

webpack prend désormais en charge le retour d'une promesse à partir du fichier de configuration. Cela permet de faire un traitement asynchrone dans votre fichier de configuration.

Vous pouvez créer une simple fonction de copie récursive qui copie votre fichier, et seulement après avoir déclenché le webpack. Par exemple:

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

permet de dire que tous vos actifs statiques sont dans un dossier "statique" au niveau racine et que vous souhaitez les copier dans le dossier de construction en conservant la structure du sous-dossier, puis dans votre fichier d'entrée)

//index.js or index.jsx

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