Jak skopiować pliki statyczne do katalogu z Webpackiem?

330

Próbuję przejść od Gulpdo Webpack. W GulpMam zadanie, które kopiuje wszystkie pliki i foldery z / static / folder do / build / folder. Jak zrobić to samo z Webpack? Czy potrzebuję wtyczki?

Witalij Korsakow
źródło
2
Łyk jest świetny do zrozumienia. po prostu zadzwoń do webpack z gulpfile.js, jeśli chcesz
Baryon Lee
Jeśli korzystasz z Laravel Mix, dostępna jest laravel.com/docs/5.8/mix#copying-files-and-directories .
Ryan

Odpowiedzi:

179

Nie musisz kopiować rzeczy, webpack działa inaczej niż gulp. Webpack to pakiet modułów i wszystko, do czego odnosisz się w swoich plikach, zostanie uwzględnione. Musisz tylko określić moduł ładujący.

Więc jeśli napiszesz:

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

Webpack najpierw spróbuje parsować plik, do którego istnieje odwołanie, jako JavaScript (ponieważ jest to ustawienie domyślne). Oczywiście to się nie powiedzie. Dlatego musisz określić moduł ładujący dla tego typu pliku. Plik - lub URL-ładowarki na przykład wziąć odwołuje plik, umieścić go w folderze wyjściowym WebPACK (która powinna być buildw danym przypadku) i powrót zakodowanego adresu URL dla tego pliku.

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

Zazwyczaj programy ładujące są stosowane przez konfigurację webpack:

// webpack.config.js

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

Oczywiście musisz najpierw zainstalować moduł ładujący pliki, aby to zadziałało.

Johannes Ewald
źródło
42
Oczywiście najpierw musisz zainstalować moduł ładujący pliki, aby to działało.Tutaj link do wyżej wymienionego „modułu ładującego pliki” . A oto jak go zainstalować i używać.
Nate
21
Nadal masz problem z ładowaniem plików HTML i wszystkich odwołań w nich.
kilianc
125
tak, jeśli chcesz dostać się do piekła wtyczek webpack, możesz użyć modułu ładującego plik, modułu ładującego css, modułu ładującego styl, modułu ładującego adres URL ... i wtedy możesz się świetnie bawić konfigurując go tak, jak potrzebujesz i googling i nie spanie :) lub możesz użyć plug-in-copy-plugin i wykonać swoją pracę ...
Kamil Tomšík
11
@ KamilTomšík Czy więc zalecasz używanie wtyczki webpack, aby uniknąć wtyczek webpack? (Żartuję. Rozumiem.)
Konrad Viltersten
12
Ok, większość zdjęć jest w css i html. Więc powinienem wymagać wszystkich tych obrazów w moich plikach JS, używając wymagania ('img.png'); aby działał z tym programem ładującym pliki? To dość szalone.
Rantiev 16.04.17
579

Wymaganie zasobów za pomocą modułu ładującego pliki to sposób, w jaki przeznaczony jest pakiet WWW ( źródło ). Jeśli jednak potrzebujesz większej elastyczności lub chcesz uzyskać czystszy interfejs, możesz również skopiować pliki statyczne bezpośrednio za pomocą my copy-webpack-plugin( npm , Github ). Dla Państwa staticna buildprzykład:

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

module.exports = {
    context: path.join(__dirname, 'your-app'),
    plugins: [
        new CopyWebpackPlugin([
            { from: 'static' }
        ])
    ]
};
kevlened
źródło
11
Jest to o wiele prostsze, gdy chcesz skopiować cały katalog (np. Statyczny HTML i inne obrazy typu kocioł)!
Arjun Mehta
6
Wykonałem lewę, dziękuję :) zrezygnowałem z programu ładującego pliki po kilku nieudanych próbach uzyskania bardzo prostej komendy. Twoja wtyczka zadziałała za pierwszym razem.
arcseldon
3
@Yan Wtyczka kopiuje pliki, jeśli się zmienią (dev-server lub webpack --watch). Jeśli nie można go skopiować, zgłoś problem.
kevlened
2
Jestem nowy w webpacku, ale trudno mi zrozumieć, dlaczego musimy używać modułu ładującego pliki / modułu ładującego url / modułu ładującego img ... zamiast po prostu je kopiować? Jakie korzyści czerpiemy z tego, powiedzmy, z programu ładującego pliki?
BreakDS
2
Ponieważ jesteś autorem wtyczki. Nie ma lepszego tempa, aby zadać to pytanie. Za pomocą wtyczki „copy-webpack-plugin” ... mogę filtrować pliki z katalogu źródłowego, aby kopiował tylko plik z pewnym rozszerzeniem np. kopiować tylko „.html”? Pozdrawiam
DevWL,
56

Jeśli chcesz skopiować pliki statyczne, możesz użyć modułu ładującego w następujący sposób:

dla plików HTML:

w pliku webpack.config.js:

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

w twoim pliku js:

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

./static/ odnosi się do położenia pliku js.

Możesz zrobić to samo z obrazami lub cokolwiek innego. Kontekst jest potężną metodą eksploracji !!

Moussa Dembélé
źródło
3
Wolę tę metodę niż moduł copy-webpack-plugin. Ponadto udało mi się uruchomić go bez użycia „& context =. / App / static” w mojej konfiguracji pakietu sieciowego. Potrzebowałem tylko linii wymaganej. Kontekstu.
Dave Landry
2
Próbuję tego, wydaje się to świetne, ale z powodu jednego małego problemu, który otrzymuję, to jest umieszczenie mojego index.htmlw podkatalogu, który tworzy o nazwie _(podkreślenie), co się dzieje?
kris
2
Kiedy mówisz „w pliku js”, co masz na myśli? Co jeśli nie mam pliku JS?
evolutionxbox
absolutnie. Ta jedna linia w skrypcie wejściowym, tzn. main.jsImportuje wszystko z staticfolderu:require.context("./static/", true, /^.*/);
Mario,
2
To fajny hack, ale jeśli kopiujesz zbyt wiele plików, zabraknie ci pamięci.
Tom
18

Jedną z zalet, o której wspomniana wtyczka copy-webpack-plug-in , która nie została wcześniej wyjaśniona, jest to, że wszystkie inne metody tu wymienione nadal łączą zasoby w pliki pakietu (i wymagają „gdzieś” lub „zaimportowania” ich gdzieś). Jeśli chcę po prostu przesuwać niektóre obrazy lub częściowe szablony, nie chcę zaśmiecać mojego pakietu javascript z bezużytecznymi odniesieniami do nich, chcę tylko, aby pliki były emitowane we właściwym miejscu. Nie znalazłem innego sposobu na zrobienie tego w pakiecie internetowym. Trzeba przyznać, że nie jest to, do czego pierwotnie przeznaczony był webpack, ale zdecydowanie jest to aktualny przypadek użycia. (@BreakDS Mam nadzieję, że to odpowiada na twoje pytanie - to tylko korzyść, jeśli chcesz)

steev
źródło
7

Powyższe sugestie są dobre. Ale, aby spróbować bezpośrednio odpowiedzieć na twoje pytanie, sugerowałbym użycie cpy-cliw skrypcie zdefiniowanym w twoim package.json.

Ten przykład oczekuje nodegdzieś na twojej ścieżce. Zainstaluj cpy-clijako zależność programistyczną:

npm install --save-dev cpy-cli

Następnie utwórz kilka plików nodejs. Jeden wykonuje kopię, a drugi wyświetla znacznik wyboru i komunikat.

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;

Dodaj skrypt w package.json. Zakładając, że istnieją skrypty<project-root>/scripts/

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

Aby uruchomić sript:

npm run copy

RnR
źródło
3
OP chciał, aby plik był przenoszony w pakiecie webowym, nie używając skryptów npm?
William S
Nawet jeśli OP chciał rozwiązać ten problem w pakiecie internetowym, możliwe jest, że uruchamia on pakiet przez npm, więc mógłby dodać go do swojego skryptu kompilacji, w którym działa webpack
mówi Piro Reinstate Monica
5

Najprawdopodobniej powinieneś użyć CopyWebpackPlugin, który został wspomniany w odpowiedzi kevlened. Alternatywnie dla niektórych rodzajów plików, takich jak .html lub .json , można również użyć modułu ładującego raw lub modułu ładującego json. Zainstaluj go przez, npm install -D raw-loadera następnie wystarczy dodać kolejny moduł ładujący do naszego webpack.config.jspliku.

Lubić:

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

Uwaga: Zrestartuj serwer webpack-dev-server, aby zmiany konfiguracji zostały wprowadzone.

Teraz możesz wymagać plików HTML przy użyciu ścieżek względnych, co znacznie ułatwia przenoszenie folderów.

template: require('./nav.html')  
Andurit
źródło
5

Sposób ładowania statycznego imagesi 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/'
          },
        }
    ]
}

Nie zapomnij zainstalować, file-loaderaby działał.

RegarBoy
źródło
Jak radzisz sobie ze zduplikowanymi nazwami plików? Lub jeszcze lepiej, znasz jakiś sposób na zachowanie oryginalnej ścieżki w nowym katalogu wyjściowym?
cantuket
W swoim projekcie nie powinieneś mieć zduplikowanej nazwy pliku o tej samej nazwie rozszerzenia. Jaki jest sens przechowywania duplikatów, jeśli ich treść jest identyczna? Jeśli nie, nazwij je inaczej w zależności od ich zawartości. Ale dlaczego miałbyś używać webpacka, jeśli chcesz zachować swoje rzeczy na oryginalnej ścieżce? Jeśli chcesz tylko tłumaczenie JS, wystarczy Babel.
RegarBoy
1
Jeśli wdrażasz programowanie oparte na komponentach (jedną z głównych zasad jest hermetyzacja, a dokładniej w tym przypadku ukrywanie informacji ) , to żadne z Twoich wspomnień nie jest istotne. tzn. kiedy ktoś dodaje nowy komponent do programu, nie powinien sprawdzać, czy istnieje inny obraz o nazwie, logo.pngani nie powinien tworzyć tępej i „miejmy nadzieję” unikatowej nazwy pliku, aby uniknąć globalnej kolizji. Z tego samego powodu używamy modułów CSS .
cantuket
1
Dlaczego chcę, aby obrazy zachowały oryginalną ścieżkę i nazwę pliku; debugowanie głównie z tego samego powodu, dla którego użyjesz sourcemaps, ale także SEO . Niezależnie od tego, odpowiedź na moje pytanie była w rzeczywistości bardzo prosta ... [path][name].[ext]i zapewniono wiele elastyczności, aby zmodyfikować to dla konkretnego środowiska lub przypadku użycia ... program ładujący
pliki
1
Biorąc to pod uwagę, wprowadziliśmy odmianę Twojego przykładu, więc dziękuję za dostarczenie!
cantuket
3

Możesz napisać bash w pakiecie.json:

# package.json
{
  "name": ...,
  "version": ...,
  "scripts": {
    "build": "NODE_ENV=production npm run webpack && cp -v <this> <that> && echo ok",
    ...
  }
}
Wiktor Pudiejew
źródło
1
W systemie Windows wystarczy użyć xcopy zamiast cp:"build": "webpack && xcopy images dist\\images\\ /S /Y && xcopy css dist\\css\\ /S /Y"
SebaGra
7
Zgadza się, więc Twoim rozwiązaniem jest mieć inny skrypt dla każdego systemu operacyjnego?
Maciej Gurban,
Tak, dla mnie skrypt dla każdego systemu operacyjnego jest akceptowalny (jest to naprawdę unix / non-unix, ponieważ skrypt na Linuxie będzie działał na Darwin lub innym POSIX * nix)
Victor Pudeyev
I ten przykład systemu Windows nie będzie działał z PowerShell jako domyślną powłoką.
Julian Knight
W przeciwieństwie do CopyWebpackPlugin ta opcja zachowuje daty plików. Problem z systemem operacyjnym może być problematyczny dla open source, ale dla mniejszych zespołów można łatwo zarządzać za pomocą Windows bash lub owijania xcopy za pomocą cp.bat.
Alien Technology
2

Utknąłem tutaj również. Copy-webpack-plugin działał dla mnie.

Jednak „copy-webpack-plugin” nie był w moim przypadku konieczny (dowiedziałem się później).

webpack ignoruje
przykład ścieżek root

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

Aby więc działało to bez użycia „copy-webpack-plugin” użyj „~” w ścieżkach

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

„~” mówi webpackowi, aby traktował „obrazy” jako moduł

Uwaga: może być konieczne dodanie katalogu nadrzędnego katalogu obrazów w

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

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

techNik
źródło
2

Plik konfiguracyjny webpack (w webpack 2) pozwala wyeksportować łańcuch obietnic, o ile ostatni krok zwraca obiekt konfiguracyjny webpack. Zobacz dokumenty konfiguracji obietnicy . Stamtąd:

webpack obsługuje teraz zwracanie obietnicy z pliku konfiguracyjnego. Umożliwia to przetwarzanie asynchroniczne w pliku konfiguracyjnym.

Możesz utworzyć prostą funkcję kopiowania rekurencyjnego, która kopiuje plik i dopiero wtedy uruchamia pakiet WWW. Na przykład:

module.exports = function(){
    return copyTheFiles( inpath, outpath).then( result => {
        return { entry: "..." } // Etc etc
    } )
}
Mentor
źródło
1

powiedzmy, że wszystkie zasoby statyczne znajdują się w folderze „statycznym” na poziomie głównym i chcesz je skopiować do folderu kompilacji, zachowując strukturę podfolderu, a następnie w pliku wejściowym)

//index.js or index.jsx

require.context("!!file?name=[path][name].[ext]&context=./static!../static/", true, /^\.\/.*\.*/);
abhisekpaul
źródło