Come copiare file statici per creare directory con Webpack?


331

Sto provando a passare da Gulpa Webpack. In GulpHo compito che copia tutti i file e cartelle da / static / cartella / build / cartella. Come fare lo stesso con Webpack? Ho bisogno di alcuni plugin?


2
Gulp è fantastico da capire. basta chiamare webpack da gulpfile.js se vuoi
Baryon Lee

Se stai usando Laravel Mix, sono disponibili laravel.com/docs/5.8/mix#copying-files-and-directories .
Ryan,

Risposte:


179

Non è necessario copiare cose in giro, il webpack funziona in modo diverso da gulp. Webpack è un modulo bundler e tutto ciò che farai riferimento nei tuoi file verrà incluso. Devi solo specificare un caricatore per questo.

Quindi se scrivi:

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

Webpack tenterà innanzitutto di analizzare il file di riferimento come JavaScript (perché è quello predefinito). Certo, ciò fallirà. Ecco perché è necessario specificare un caricatore per quel tipo di file. Il file - o url-loader, ad esempio, prende il file di riferimento, lo inserisce nella cartella di output del webpack (che dovrebbe essere buildnel tuo caso) e restituisce l'URL con hash per quel file.

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

Di solito i caricatori vengono applicati tramite la configurazione del webpack:

// webpack.config.js

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

Ovviamente devi prima installare il caricatore di file per farlo funzionare.


42
" Ovviamente devi prima installare il caricatore di file per farlo funzionare. " Link al summenzionato "caricatore di file" qui . Ed ecco come installarlo e usarlo.
Nate,

21
Hai ancora il problema dei file HTML e tutti i riferimenti in essi non vengono caricati.
Kilianc,

126
sì, se vuoi entrare nell'inferno dei plugin di webpack, puoi usare file-loader, css-loader, style-loader, url-loader, ... e poi puoi divertirti a configurarlo nel modo che ti serve e googling e non dormire :) oppure puoi usare copy-webpack-plugin e fare il tuo lavoro ...
Kamil Tomšík

11
@ KamilTomšík Quindi la tua raccomandazione è che dovremmo usare un plugin webpack per evitare plugin webpack? (Sto scherzando. Ho
capito il

12
Ok, la maggior parte di tutte le immagini sono in CSS e HTML. Quindi dovrei richiedere tutte queste immagini nei miei file JS usando require ('img.png'); farlo funzionare con quel caricatore di file? È una cosa abbastanza pazza.
Rantiev,

581

La richiesta di risorse utilizzando il modulo caricatore di file è il modo in cui si intende utilizzare il webpack ( fonte ). Tuttavia, se hai bisogno di maggiore flessibilità o desideri un'interfaccia più pulita, puoi anche copiare i file statici direttamente usando my copy-webpack-plugin( npm , Github ). Per la vostra staticper buildesempio:

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

module.exports = {
    context: path.join(__dirname, 'your-app'),
    plugins: [
        new CopyWebpackPlugin([
            { from: 'static' }
        ])
    ]
};

11
Questo è molto più semplice quando si desidera copiare un'intera directory (es. Html statico e altre immagini del bollettino)!
Arjun Mehta,

6
Il trucco, grazie :) ha rinunciato al caricatore di file dopo diversi tentativi falliti per farlo eseguire un comando molto semplice. il tuo plugin ha funzionato la prima volta.
arcseldon,

3
@Yan Il plug-in copia nuovamente i file se cambiano (dev-server o webpack --watch). Se non ti sta copiando, ti preghiamo di presentare un problema.
kevlened,

2
Sono nuovo nel webpack, ma non riesco a capire perché dobbiamo usare file-loader / url-loader / img-loader ... invece di copiarli? Qual è il vantaggio che otteniamo facendo questo con, diciamo, caricatore di file?
BreakDS

2
Dal momento che sei l'autore del plugin. Non c'è ritmo migliore per porre questa domanda. Utilizzando il plug-in "copy-webpack-plugin" ... posso filtrare i file dalla directory di origine in modo che copi il file solo con una certa estensione del file ex. copia solo ".html"? Saluti
DevWL

56

Se vuoi copiare i tuoi file statici puoi usare il caricatore di file in questo modo:

per i file html:

in webpack.config.js:

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

nel tuo file js:

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

./static/ è relativo alla posizione del file js.

Puoi fare lo stesso con le immagini o altro. Il contesto è un metodo potente da esplorare !!


3
Preferisco questo metodo al modulo copia-webpack-plugin. Inoltre, sono stato in grado di farlo funzionare senza usare "& context =. / App / static" nella mia configurazione del webpack. Mi serviva solo la linea request.context.
Dave Landry,

2
Ci sto provando, sembra fantastico, ma per un piccolo problema che sto riscontrando, ovvero che sta mettendo il mio index.htmlin una sottodirectory che sta creando chiamato _(trattino basso), cosa sta succedendo?
Kris,

2
Quando dici "nel tuo file js" cosa intendi? Cosa succede se non ho un file JS?
evolutionxbox

assolutamente. Questa riga nello script di entrata, ovvero main.jssta importando tutto all'interno della staticcartella:require.context("./static/", true, /^.*/);
Mario,

2
Questo è un trucco accurato ma se stai copiando troppi file, rimarrai senza memoria.
Tom,

18

Un vantaggio che il summenzionato plug-in copy-webpack porta che non è stato spiegato in precedenza è che tutti gli altri metodi menzionati qui raggruppano ancora le risorse nei file bundle (e richiedono di "richiederli" o "importarli" da qualche parte). Se voglio solo spostare alcune immagini o alcuni template parziali, non voglio ingombrare il mio file bundle javascript con riferimenti inutili ad essi, voglio solo che i file vengano emessi nel posto giusto. Non ho trovato nessun altro modo per farlo nel webpack. È vero che non è stato progettato per il webpack originariamente, ma è sicuramente un caso d'uso attuale. (@BreakDS spero che questo risponda alla tua domanda - è solo un vantaggio se lo vuoi)


7

I suggerimenti sopra sono buoni. Ma per provare a rispondere direttamente alla tua domanda ti suggerirei di usarlo cpy-cliin uno script definito nel tuopackage.json .

Questo esempio prevede nodeun punto del percorso. Installa cpy-clicome dipendenza di sviluppo:

npm install --save-dev cpy-cli

Quindi crea un paio di file nodejs. Uno per eseguire la copia e l'altro per visualizzare un segno di spunta e un messaggio.

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;

Aggiungi lo script in package.json. Supponendo che gli script siano presenti<project-root>/scripts/

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

Per eseguire lo script:

npm run copy


3
OP voleva realizzare lo spostamento del file all'interno del webpack, non usando gli script npm?
William S,

Anche quando OP voleva risolvere questo all'interno del webpack, è possibile che stia eseguendo il webpack attraverso npm, quindi potrebbe aggiungerlo al suo script di build in cui viene eseguito il webpack
Piro dice Reinstate Monica

5

Molto probabilmente dovresti usare CopyWebpackPlugin che è stato menzionato nella risposta kevlened. In alternativa per alcuni tipi di file come .html o .json è anche possibile utilizzare raw-loader o json-loader. Installalo tramite npm install -D raw-loadere quindi non ti resta che aggiungere un altro caricatore al nostro webpack.config.jsfile.

Piace:

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

Nota: riavviare webpack-dev-server per rendere effettive eventuali modifiche alla configurazione.

E ora puoi richiedere file html usando percorsi relativi, questo rende molto più facile spostare le cartelle.

template: require('./nav.html')  

5

Il modo in cui carico statico imagese 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/'
          },
        }
    ]
}

Non dimenticare di installare file-loaderper farlo funzionare.


Come gestite i nomi di file duplicati? O meglio ancora, conosci un modo per preservare il percorso originale nella nuova directory di output?
cantuket

Non dovresti avere un nome file duplicato con lo stesso nome di estensione nel tuo progetto. Che senso ha conservare i duplicati se il loro contenuto è identico? In caso contrario, denominali in modo diverso in base al loro contenuto. Ma perché dovresti usare il webpack se vuoi mantenere le tue cose nel percorso originale? Se vuoi solo la traduzione JS, Babel dovrebbe essere abbastanza.
RegarBoy,

1
Se stai implementando lo sviluppo basato su componenti (uno dei principi principali dei quali è l'incapsulamento e più specificamente in questo caso nascondere le informazioni ) , allora nulla di ciò che hai menzionato è pertinente. cioè quando qualcuno aggiunge un nuovo componente al programma non dovrebbe aver bisogno di controllare se c'è un'altra immagine chiamata logo.pngné dovrebbe creare un nome file ottuso e "si spera" univoco per evitare la collisione globale. Stesso motivo per cui utilizziamo i moduli CSS .
cantuket,

1
Per quanto riguarda il motivo per cui voglio che le immagini mantengano il percorso e il nome file originali; debug principalmente, stesso motivo per cui dovresti usare sourcemap, ma anche SEO . Indipendentemente da ciò, la risposta alla mia domanda era in realtà molto semplice ... [path][name].[ext]e c'è molta flessibilità fornita per modificarlo per un ambiente specifico o caso d'uso ... file-loader
cantuket

1
Detto questo, abbiamo implementato una variante del tuo esempio, quindi grazie per averci fornito!
cantuket,

3

Puoi scrivere bash nel tuo package.json:

# package.json
{
  "name": ...,
  "version": ...,
  "scripts": {
    "build": "NODE_ENV=production npm run webpack && cp -v <this> <that> && echo ok",
    ...
  }
}

1
In Windows, basta usare xcopy invece di cp:"build": "webpack && xcopy images dist\\images\\ /S /Y && xcopy css dist\\css\\ /S /Y"
SebaGra,

7
Bene, quindi la tua soluzione è quella di avere uno script diverso per ciascun sistema operativo?
Maciej Gurban,

Sì, per me uno script per ciascun sistema operativo è accettabile (è davvero unix / non-unix, poiché uno script su Linux verrà eseguito su Darwin o un altro POSIX * nix)
Victor Pudeyev,

E quell'esempio di Windows non funzionerà nemmeno con PowerShell come shell predefinita.
Julian Knight,

A differenza di CopyWebpackPlugin, questa opzione mantiene le date dei file. Il problema del sistema operativo potrebbe essere problematico per l'open source, ma per i team più piccoli è facilmente gestibile con Windows bash o il wrapping di xcopy con cp.bat.
Alien Technology

2

Anche io ero bloccato qui. copy-webpack-plugin ha funzionato per me.

Tuttavia, nel mio caso "copy-webpack-plugin" non era necessario (l'ho imparato in seguito).

webpack ignora l'
esempio dei percorsi di root

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

Quindi, per farlo funzionare senza usare 'copy-webpack-plugin' usa '~' nei percorsi

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

'~' dice al webpack di considerare 'images' come un modulo

nota: potrebbe essere necessario aggiungere la directory principale della directory images in

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

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


2

Il file di configurazione del webpack (nel webpack 2) consente di esportare una catena di promesse, purché l'ultimo passaggio restituisca un oggetto di configurazione del webpack. Consulta i documenti di configurazione delle promesse . Da li:

webpack ora supporta la restituzione di una Promessa dal file di configurazione. Ciò consente di eseguire l'elaborazione asincrona nel file di configurazione.

È possibile creare una semplice funzione di copia ricorsiva che copia il file e solo successivamente si attiva il webpack. Per esempio:

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

1

diciamo che tutte le risorse statiche si trovano in una cartella "statica" a livello di root e si desidera copiarle nella cartella build mantenendo la struttura della sottocartella, quindi nel file di immissione) basta inserire

//index.js or index.jsx

require.context("!!file?name=[path][name].[ext]&context=./static!../static/", true, /^\.\/.*\.*/);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.