Bagaimana cara menyalin file statis untuk membangun direktori dengan Webpack?

331

Saya mencoba untuk pindah dari Gulpke Webpack. Di GulpSaya punya tugas yang menyalin semua file dan folder dari / static / folder ke / build / folder. Bagaimana caranya melakukan hal yang sama Webpack? Apakah saya memerlukan plugin?

Vitalii Korsakov
sumber
2
Gulp bagus untuk dipahami. telepon saja webpack dari gulpfile.js jika Anda mau
Baryon Lee
Jika Anda menggunakan Laravel Mix, laravel.com/docs/5.8/mix#copying-files-and-directories tersedia.
Ryan

Jawaban:

179

Anda tidak perlu menyalin banyak hal, webpack bekerja berbeda dari tegukan. Webpack adalah bundler modul dan semua yang Anda rujuk dalam file Anda akan disertakan. Anda hanya perlu menentukan loader untuk itu.

Jadi, jika Anda menulis:

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

Webpack pertama-tama akan mencoba mem-parsing file yang direferensikan sebagai JavaScript (karena itu defaultnya). Tentu saja itu akan gagal. Itu sebabnya Anda perlu menentukan loader untuk tipe file itu. The File - atau url-loader misalnya mengambil file direferensikan, memasukkannya ke dalam folder output Webpack (yang harus builddalam kasus Anda) dan mengembalikan url hash untuk file itu.

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

Biasanya loader diterapkan melalui konfigurasi webpack:

// webpack.config.js

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

Tentu saja Anda perlu menginstal file-loader terlebih dahulu untuk membuat ini berfungsi.

Johannes Ewald
sumber
42
" Tentu saja Anda perlu menginstal file-loader terlebih dahulu untuk membuatnya bekerja. " Tautan ke "file-loader" yang disebutkan di sini . Dan di sini adalah cara menginstal dan menggunakannya.
Nate
21
Anda masih memiliki masalah file HTML dan semua referensi di dalamnya tidak dimuat.
kilianc
126
ya, jika Anda ingin masuk ke plugin webpack, Anda dapat menggunakan file-loader, css-loader, style-loader, url-loader, ... dan kemudian Anda dapat bersenang-senang mengonfigurasinya seperti yang Anda butuhkan dan googling dan tidak tidur :) atau Anda dapat menggunakan copy-webpack-plugin dan menyelesaikan pekerjaan Anda ...
Kamil Tomšík
11
@ KamilTomšík Jadi rekomendasi Anda adalah bahwa kita harus menggunakan plugin webpack untuk menghindari plugin webpack? (Hanya bercanda. Saya mengerti maksud Anda.)
Konrad Viltersten
12
Ok, sebagian besar dari semua gambar dalam css dan html. Jadi saya harus meminta semua gambar ini dalam file JS saya menggunakan require ('img.png'); untuk membuatnya bekerja dengan pemuat file itu? Itu hal yang cukup gila.
Rantiev
581

Membutuhkan aset menggunakan modul file-loader adalah cara webpack dimaksudkan untuk digunakan ( sumber ). Namun, jika Anda membutuhkan fleksibilitas yang lebih besar atau ingin antarmuka yang lebih bersih, Anda juga dapat menyalin file statis langsung menggunakan saya copy-webpack-plugin( NPM , Github ). Untuk Anda staticke buildcontoh:

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

module.exports = {
    context: path.join(__dirname, 'your-app'),
    plugins: [
        new CopyWebpackPlugin([
            { from: 'static' }
        ])
    ]
};
kevlened
sumber
11
Ini jauh lebih sederhana ketika Anda ingin menyalin seluruh direktori (mis. Html statis, dan gambar boilerplate lainnya)!
Arjun Mehta
6
Apakah caranya, terima kasih :) menyerah pada pemuat file setelah beberapa upaya gagal untuk membuatnya melakukan perintah yang sangat sederhana. plugin Anda berfungsi pertama kali.
arcseldon
3
@Yan Plugin tidak menyalin ulang file jika diubah (dev-server atau webpack --watch). Jika tidak menyalin untuk Anda, silakan ajukan masalah.
kevlened
2
Saya baru mengenal webpack, tetapi saya kesulitan memahami mengapa kita perlu menggunakan file-loader / url-loader / img-loader ... alih-alih hanya menyalinnya? Apa manfaatnya dari melakukan ini dengan, katakanlah, pemuat file?
BreakDS
2
Karena Anda adalah pembuat plugin. Tidak ada langkah yang lebih baik untuk mengajukan pertanyaan ini. Menggunakan plugin "copy-webpack-plugin" ... dapatkah saya memfilter file dari direktori sumber sehingga hanya menyalin file dengan ekstensi file ex tertentu. salin saja ".html"? Salam
DevWL
56

Jika Anda ingin menyalin file statis, Anda dapat menggunakan pemuat file dengan cara ini:

untuk file html:

di webpack.config.js:

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

dalam file js Anda:

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

./static/ adalah relatif ke tempat file js Anda.

Anda dapat melakukan hal yang sama dengan gambar atau apa pun. Konteksnya adalah metode yang ampuh untuk dijelajahi !!

Moussa Dembélé
sumber
3
Saya lebih suka metode ini daripada modul copy-webpack-plugin. Selain itu, saya dapat membuatnya berfungsi tanpa menggunakan "& context =. / App / static" di konfigurasi webpack saya. Saya hanya perlu baris require.context.
Dave Landry
2
Saya mencoba ini, sepertinya hebat tetapi untuk satu masalah kecil yang saya dapatkan, yaitu menempatkan saya index.htmlke dalam subdirektori yang dibuatnya disebut _(garis bawah), apa yang terjadi?
Keris
2
Ketika Anda mengatakan "dalam file js Anda", apa maksud Anda? Bagaimana jika saya tidak memiliki file JS?
evolutionxbox
benar. Ini satu baris dalam skrip entri, yaitu main.jsmengimpor segala sesuatu di dalam staticfolder:require.context("./static/", true, /^.*/);
Mario
2
Ini adalah retasan yang rapi tetapi jika Anda menyalin terlalu banyak file, Anda akan kehabisan memori.
Tom
18

Satu keuntungan yang dibawa oleh copy-webpack-plugin yang belum dijelaskan sebelumnya adalah bahwa semua metode lain yang disebutkan di sini masih membundel sumber daya ke dalam file bundel Anda (dan mengharuskan Anda untuk "mengharuskan" atau "mengimpor" mereka di suatu tempat). Jika saya hanya ingin memindahkan beberapa gambar di sekitar atau sebagian parsial template, saya tidak ingin mengacaukan file bundel javascript saya dengan referensi yang tidak berguna untuk mereka, saya hanya ingin file dipancarkan di tempat yang tepat. Saya belum menemukan cara lain untuk melakukan ini di webpack. Diakui itu bukan apa webpack awalnya dirancang untuk, tapi itu pasti kasus penggunaan saat ini. (@BreakDS Saya harap ini menjawab pertanyaan Anda - itu hanya menguntungkan jika Anda menginginkannya)

steev
sumber
7

Saran di atas bagus. Tetapi untuk mencoba menjawab pertanyaan Anda secara langsung, saya sarankan untuk menggunakan cpy-cliskrip yang ditentukan dalam package.json.

Contoh ini mengharapkan nodesuatu tempat di jalur Anda. Instal cpy-clisebagai ketergantungan pengembangan:

npm install --save-dev cpy-cli

Kemudian buat beberapa file nodejs. Satu untuk melakukan penyalinan dan yang lainnya untuk menampilkan tanda centang dan pesan.

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;

Tambahkan skrip di package.json. Dengan asumsi skrip berada dalam<project-root>/scripts/

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

Untuk menjalankan sript:

npm run copy

RnR
sumber
3
OP ingin menyelesaikan file yang bergerak di dalam webpack, tidak menggunakan skrip npm?
William S
Bahkan ketika OP ingin menyelesaikan ini di dalam webpack, ada kemungkinan dia menjalankan webpack melalui npm, jadi dia bisa menambahkannya ke skrip build-nya di mana webpack dijalankan
Piro mengatakan Reinstate Monica
5

Kemungkinan besar Anda harus menggunakan CopyWebpackPlugin yang disebutkan dalam jawaban kevlened. Atau untuk beberapa jenis file seperti .html atau .json, Anda juga dapat menggunakan pemuat mentah atau pemuat json. Instal via npm install -D raw-loaderdan kemudian yang perlu Anda lakukan adalah menambahkan loader lain ke webpack.config.jsfile kami .

Suka:

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

Catatan: Mulai ulang webpack-dev-server agar perubahan konfigurasi diterapkan.

Dan sekarang Anda dapat memerlukan file html menggunakan jalur relatif, ini membuatnya lebih mudah untuk memindahkan folder.

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

Cara saya memuat statis imagesdan 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/'
          },
        }
    ]
}

Jangan lupa untuk menginstal file-loaderagar berfungsi.

RegarBoy
sumber
Bagaimana Anda menangani nama file duplikat? Atau lebih baik lagi, Anda tahu cara untuk mempertahankan jalur asli di direktori keluaran baru?
cantuket
Anda seharusnya tidak memiliki nama file duplikat dengan nama ekstensi yang sama di proyek Anda. Apa gunanya menyimpan duplikat jika kontennya identik? Jika tidak, maka beri nama berbeda menurut kontennya. Padahal mengapa Anda menggunakan webpack jika Anda ingin menyimpan barang-barang Anda di jalur asli? Jika Anda hanya menginginkan terjemahan JS maka Babel harus cukup.
RegarBoy
1
Jika Anda menerapkan pengembangan berbasis komponen (salah satu prinsip utama di antaranya adalah enkapsulasi dan lebih khusus dalam hal ini menyembunyikan informasi ) , maka tidak satu pun dari yang Anda sebutkan terkait. yaitu ketika seseorang menambahkan komponen baru ke program mereka tidak perlu memeriksa apakah ada gambar lain yang dinamai logo.pngjuga mereka tidak harus membuat nama pengguna yang tumpul dan "mudah-mudahan" unik untuk menghindari tabrakan global. Alasan yang sama kami menggunakan Modul CSS .
cantuket
1
Mengapa saya ingin gambar mempertahankan path asli dan nama file; kebanyakan debug, alasan yang sama Anda akan menggunakan sourcemaps, tetapi juga SEO . Apapun, jawaban atas pertanyaan saya sebenarnya sangat sederhana ... [path][name].[ext]dan ada banyak fleksibilitas yang diberikan untuk memodifikasi ini untuk lingkungan atau kasus penggunaan khusus ... file-loader
cantuket
1
Yang sedang berkata kami memang menerapkan variasi contoh Anda jadi terima kasih telah menyediakan!
cantuket
3

Anda dapat menulis bash di package.json Anda:

# package.json
{
  "name": ...,
  "version": ...,
  "scripts": {
    "build": "NODE_ENV=production npm run webpack && cp -v <this> <that> && echo ok",
    ...
  }
}
Victor Pudeyev
sumber
1
Di Windows, cukup gunakan xcopy sebagai ganti cp:"build": "webpack && xcopy images dist\\images\\ /S /Y && xcopy css dist\\css\\ /S /Y"
SebaGra
7
Benar, jadi solusi Anda adalah memiliki skrip yang berbeda untuk setiap OS?
Maciej Gurban
Ya, bagi saya skrip untuk setiap OS dapat diterima (ini benar-benar unix / non-unix, karena skrip di linux akan berjalan di Darwin atau POSIX * nix lain)
Victor Pudeyev
Dan contoh Windows itu tidak akan berfungsi dengan PowerShell sebagai shell default.
Julian Knight
Tidak seperti CopyWebpackPlugin, opsi ini menyimpan tanggal file. Masalah OS mungkin bermasalah untuk open source, tetapi untuk tim yang lebih kecil mudah dikelola dengan Windows bash atau membungkus xcopy dengan cp.bat.
Alien Technology
2

Saya terjebak di sini juga. copy-webpack-plugin bekerja untuk saya.

Namun, 'copy-webpack-plugin' tidak diperlukan dalam kasus saya (saya pelajari nanti).

webpack mengabaikan
contoh path root

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

Oleh karena itu, untuk membuatnya bekerja tanpa menggunakan 'copy-webpack-plugin' gunakan '~' di jalur

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

'~' memberi tahu webpack untuk mempertimbangkan 'gambar' sebagai modul

Catatan: Anda mungkin harus menambahkan direktori induk direktori gambar di

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

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

techNik
sumber
2

File konfigurasi webpack (di webpack 2) memungkinkan Anda untuk mengekspor rantai janji, selama langkah terakhir mengembalikan objek konfigurasi webpack. Lihat dokumen konfigurasi janji . Dari sana:

webpack sekarang mendukung pengembalian Janji dari file konfigurasi. Ini memungkinkan untuk melakukan pemrosesan async dalam file konfigurasi Anda.

Anda dapat membuat fungsi salin rekursif sederhana yang menyalin file Anda, dan hanya setelah itu memicu webpack. Misalnya:

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

katakanlah semua aset statis Anda berada di folder "statis" di tingkat root dan Anda ingin menyalinnya ke folder build yang mempertahankan struktur subfolder, lalu di file entri Anda) cukup masukkan

//index.js or index.jsx

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