Como copiar arquivos estáticos para criar diretório com o Webpack?

331

Estou tentando passar de Gulppara Webpack. No Gulptenho tarefa que copia todos os arquivos e pastas de / static / folder para / build / folder. Como fazer o mesmo com Webpack? Preciso de algum plugin?

Vitalii Korsakov
fonte
2
Gole é ótimo de entender. apenas chamar Webpack de gulpfile.js se você quiser
Baryon Lee
Se você estiver usando o Laravel Mix, laravel.com/docs/5.8/mix#copying-files-and-directories está disponível.
22419 Ryan

Respostas:

179

Você não precisa copiar as coisas, o webpack funciona diferente do gulp. O Webpack é um empacotador de módulos e tudo o que você referenciar em seus arquivos será incluído. Você só precisa especificar um carregador para isso.

Então, se você escrever:

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

O Webpack tentará primeiro analisar o arquivo referenciado como JavaScript (porque esse é o padrão). Claro, isso irá falhar. É por isso que você precisa especificar um carregador para esse tipo de arquivo. O arquivo - ou url-loader, por exemplo, pega o arquivo referenciado, coloca-o na pasta de saída do webpack (que deve estar buildno seu caso) e retorna o URL do hash para esse arquivo.

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

Normalmente, os carregadores são aplicados através da configuração do webpack:

// webpack.config.js

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

Claro que você precisa instalar o carregador de arquivos primeiro para fazer isso funcionar.

Johannes Ewald
fonte
42
" Claro que você precisa instalar o carregador de arquivos primeiro para fazer isso funcionar. " Link para o "carregador de arquivos" acima mencionado aqui . E aqui está como instalar e usá-lo.
Nate
21
Você ainda tem o problema de arquivos HTML e todas as referências nelas não estão sendo carregadas.
kilianc 14/12/2015
126
Sim, se você quiser entrar no inferno dos plugins do Webpack, use o carregador de arquivos, o css-loader, o style-loader, o url-loader, ... e pesquisando e não-dormir :) ou você pode usar copy-Webpack-plugin e fazer o seu trabalho ...
Kamil Tomšík
11
@ KamilTomšík Então, sua recomendação é que devemos usar um plug-in do webpack para evitar plugins do webpack? (. Brincadeirinha eu tenho o seu ponto.)
Konrad Viltersten
12
Ok, a maior parte de todas as imagens está em css e html. Então, eu deveria exigir todas essas imagens nos meus arquivos JS usando require ('img.png'); fazê-lo funcionar com esse carregador de arquivos? Isso é uma loucura.
Rantiev 16/04
581

Exigir ativos usando o módulo do carregador de arquivos é a maneira como o webpack deve ser usado ( origem ). No entanto, se você precisar de maior flexibilidade ou desejar uma interface mais limpa, também poderá copiar arquivos estáticos diretamente usando my copy-webpack-plugin( npm , Github ). Para sua staticpara buildexemplo:

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

module.exports = {
    context: path.join(__dirname, 'your-app'),
    plugins: [
        new CopyWebpackPlugin([
            { from: 'static' }
        ])
    ]
};
kevlened
fonte
11
Isso é muito mais simples quando você deseja copiar um diretório inteiro (por exemplo, html estático e outras imagens padrão)!
Arjun Mehta
6
Fiz o truque, obrigado :) desistiu do carregador de arquivos após várias tentativas fracassadas de fazê-lo executar um comando muito simples. seu plugin funcionou pela primeira vez.
Arcseldon
3
@Yan O plugin copia novamente os arquivos se eles mudarem (dev-server ou webpack --watch). Se não estiver copiando para você, registre um problema.
kevlened
2
Eu sou novo no webpack, mas estou com dificuldades para entender por que precisamos usar o carregador de arquivos / url-loader / img-loader ... em vez de apenas copiá-los? Qual é o benefício que ganhamos ao fazer isso com, digamos, carregador de arquivos?
BreakDS
2
Desde que você é o autor do plugin. Não há melhor ritmo para fazer esta pergunta. Usando o plug-in "copy-webpack-plugin" ... posso filtrar os arquivos do diretório de origem para que ele apenas copie o arquivo com certa extensão de arquivo ex. copiar apenas ".html"? Atenciosamente
DevWL
56

Se você deseja copiar seus arquivos estáticos, pode usar o carregador de arquivos desta maneira:

para arquivos html:

no webpack.config.js:

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

no seu arquivo js:

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

./static/ é relativo a onde está o seu arquivo js.

Você pode fazer o mesmo com imagens ou o que for. O contexto é um método poderoso para explorar !!

Moussa Dembélé
fonte
3
Eu prefiro esse método sobre o módulo copy-webpack-plugin. Além disso, consegui fazê-lo funcionar sem usar "& context =. / App / static" na minha configuração do webpack. Eu só precisava da linha require.context.
Dave Landry
2
Estou tentando isso, parece ótimo, mas para um pequeno problema que estou recebendo, que é o de colocar o meu index.htmlem um subdiretório que está criando chamado _(sublinhado), o que está acontecendo?
kris
2
Quando você diz "no seu arquivo js", o que você quer dizer? E se eu não tiver um arquivo JS?
evolutionxbox
absolutamente. Esta linha no script de entrada, ou seja, main.jsestá importando tudo dentro da staticpasta:require.context("./static/", true, /^.*/);
Mario
2
Este é um truque simples, mas se você copiar muitos arquivos, ficará sem memória.
Tom
18

Uma vantagem que o acima mencionado copy-webpack-plugin traz e que não foi explicado antes é que todos os outros métodos mencionados aqui ainda agrupam os recursos em seus arquivos de pacote configurável (e exigem que você os "exija" ou "importe" em algum lugar). Se eu quiser apenas mover algumas imagens ou partes do modelo, não quero desordenar meu arquivo de pacote javascript com referências inúteis a elas, só quero que os arquivos sejam emitidos no lugar certo. Não encontrei nenhuma outra maneira de fazer isso no webpack. É certo que não é para o que o webpack foi projetado originalmente, mas é definitivamente um caso de uso atual. (@BreakDS Espero que isso responda à sua pergunta - é apenas um benefício se você quiser)

steev
fonte
7

As sugestões acima são boas. Mas, para tentar responder sua pergunta diretamente, sugiro usar cpy-clium script definido em sua package.json.

Este exemplo espera nodepara algum lugar no seu caminho. Instale cpy-clicomo uma dependência de desenvolvimento:

npm install --save-dev cpy-cli

Em seguida, crie alguns arquivos nodejs. Um para fazer a cópia e o outro para exibir uma marca de seleção e uma mensagem.

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;

Adicione o script package.json. Supondo que os scripts estejam em<project-root>/scripts/

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

Para executar o sript:

npm run copy

RnR
fonte
3
A OP queria realizar a movimentação do arquivo dentro do webpack, sem usar scripts npm?
William S
Mesmo quando o OP quis resolver isso dentro do webpack, é possível que ele esteja executando o webpack através do npm, para que ele possa ser adicionado ao seu script de construção onde o webpack é executado
Piro diz Reinstate Monica
5

Provavelmente você deve usar o CopyWebpackPlugin, mencionado na resposta kevlened. Como alternativa para algum tipo de arquivo como .html ou .json, você também pode usar o raw-loader ou o json-loader. Instale-o via npm install -D raw-loadere, em seguida, o que você só precisa fazer é adicionar outro carregador ao nosso webpack.config.jsarquivo.

Gostar:

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

Nota: Reinicie o webpack-dev-server para que quaisquer alterações na configuração entrem em vigor.

E agora você pode exigir arquivos html usando caminhos relativos, isso facilita muito a movimentação de pastas.

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

A maneira como carrego estática 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/'
          },
        }
    ]
}

Não se esqueça de instalar file-loaderpara que isso funcione.

RegarBoy
fonte
Como você lida com nomes de arquivos duplicados? Ou melhor ainda, você conhece alguma maneira de preservar o caminho original no novo diretório de saída?
cantuket
Você não deve ter um nome de arquivo duplicado com o mesmo nome de extensão no seu projeto. Qual o sentido de manter duplicatas, se o conteúdo for idêntico? Caso contrário, dê um nome diferente de acordo com o conteúdo. No entanto, por que você usaria o webpack se deseja manter suas coisas no caminho original? Se você deseja apenas a tradução JS, o Babel deve ser suficiente.
RegarBoy 02/02/19
1
Se você estiver implementando o desenvolvimento baseado em componentes (um dos principais princípios é o encapsulamento e, mais especificamente, o ocultação de informações ) , nada do que você mencionou é pertinente. ou seja, quando alguém adiciona um novo componente ao programa, ele não precisa verificar se há outra imagem chamada logo.pngnem deve criar um nome de arquivo obtuso e "esperançosamente" exclusivo para evitar colisões globais. Mesmo motivo pelo qual usamos módulos CSS .
cantuket 2/02/19
1
Por que eu quero que as imagens mantenham o caminho e o nome do arquivo originais; depuração principalmente, pelo mesmo motivo que você usaria mapas de origem, mas também SEO . Independentemente disso, a resposta à minha pergunta era realmente muito simples ... [path][name].[ext]e há uma abundância de flexibilidade previsto para modificar este para o ambiente específico ou caso de uso ... arquivo-loader
cantuket
1
Dito isto, implementamos uma variação do seu exemplo, portanto, obrigado por fornecer!
cantuket 2/02/19
3

Você pode escrever o bash no seu package.json:

# package.json
{
  "name": ...,
  "version": ...,
  "scripts": {
    "build": "NODE_ENV=production npm run webpack && cp -v <this> <that> && echo ok",
    ...
  }
}
Victor Pudeyev
fonte
1
No Windows, basta usar o xcopy em vez do cp:"build": "webpack && xcopy images dist\\images\\ /S /Y && xcopy css dist\\css\\ /S /Y"
SebaGra
7
Certo, então sua solução é ter um script diferente para cada sistema operacional?
Maciej Gurban
Sim, para mim um script para cada OS é aceitável (que é realmente unix / não-Unix, desde um script no linux será executado em Darwin ou de outra POSIX * nix)
Victor Pudeyev
E esse exemplo do Windows também não funcionará com o PowerShell como shell padrão.
Julian Knight
Ao contrário do CopyWebpackPlugin, esta opção mantém as datas dos arquivos. O problema do sistema operacional pode ser problemático para código aberto, mas para equipes menores é facilmente gerenciado com o Windows bash ou com o xcopy no cp.bat.
Alien Technology
2

Eu também estava preso aqui. O copy-webpack-plugin funcionou para mim.

No entanto, 'copy-webpack-plugin' não era necessário no meu caso (aprendi mais tarde).

Webpack ignora caminhos raiz
exemplo

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

Portanto, para fazer isso funcionar sem usar 'copy-webpack-plugin', use '~' nos caminhos

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

'~' diz ao webpack para considerar 'imagens' como um módulo

nota: pode ser necessário adicionar o diretório pai do diretório de imagens em

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

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

techNik
fonte
2

O arquivo de configuração do webpack (no webpack 2) permite exportar uma cadeia de promessas, desde que a última etapa retorne um objeto de configuração do webpack. Consulte os documentos de configuração da promessa . De lá:

O webpack agora suporta o retorno de uma promessa do arquivo de configuração. Isso permite fazer o processamento assíncrono no seu arquivo de configuração.

Você pode criar uma função de cópia recursiva simples que copia seu arquivo e somente depois disso dispara o webpack. Por exemplo:

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

digamos que todos os seus recursos estáticos estão em uma pasta "estática" no nível raiz e você deseja copiá-los para a pasta de construção, mantendo a estrutura da subpasta e, em seguida, no seu arquivo de entrada) basta colocar

//index.js or index.jsx

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