Як скопіювати статичні файли для створення каталогу за допомогою Webpack?


330

Я намагаюся перейти з Gulpна Webpack. У Gulpмене є завдання, яке копіює всі файли та папки з / static / folder у / build / folder. Як зробити те ж саме з Webpack? Мені потрібен плагін?


2
Gulp чудово розуміти. просто зателефонуйте на веб-пакет з gulpfile.js, якщо хочете
Баріон Лі

Якщо ви використовуєте Laravel Mix, доступний laravel.com/docs/5.8/mix#copying-files-and-directories .
Райан

Відповіді:


179

Копіювати речі не потрібно, веб-пакет працює інакше, ніж глотком. Webpack є модулем, і все, що ви посилаєтеся у своїх файлах, буде включено. Для цього просто потрібно вказати завантажувач.

Тож якщо ви пишете:

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

Спочатку Webpack спробує проаналізувати посилається файл як JavaScript (тому що це за замовчуванням). Звичайно, це не вдасться. Ось чому вам потрібно вказати завантажувач для цього типу файлів. Наприклад, файл - або завантажувач URL-адрес, беруть згаданий файл, поміщають його у вихідну папку webpack (яка має бути buildу вашому випадку) та повертають хешований URL-адресу для цього файлу.

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

Зазвичай завантажувачі застосовуються через конфігурацію веб-пакету:

// webpack.config.js

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

Звичайно, для цього потрібно спочатку встановити завантажувач файлів.


42
« Звичайно , вам потрібно встановити файл-завантажувач першим , щоб зробити цю роботу. » Посилання на вищезгаданий «файл-навантажувач» тут . А ось як її встановити та використовувати.
Нейт

21
У вас все ще є проблема HTML-файлів, і всі посилання в них не завантажуються.
kilianc

125
так, якщо ви хочете потрапити в пекло плагінів webpack, ви можете використовувати завантажувач файлів, завантажувач css, завантажувач стилів, url-завантажувач, ... і тоді ви зможете чудово налаштувати його так, як вам потрібно і гугла, і не спить :) або ви можете скопіювати плагін copy-webpack і приступити до своєї роботи ...
Kamil Tomšík

11
@ KamilTomšík Ваша рекомендація полягає в тому, що ми повинні використовувати плагін webpack, щоб уникнути плагінів webpack? (Просто жартую. Я зрозумів вашу думку.)
Конрад Вільтерстен

12
Гаразд, більша частина всіх зображень знаходиться у css та html. Тож чи потрібно мені вимагати всі ці зображення у моїх файлах JS, використовуючи requ ('img.png'); щоб він працював із цим завантажувачем файлів? Це зовсім божевільна річ.
Рантьєв

579

Потрібні активи, що використовують модуль завантажувача файлів, - це спосіб використання webpack ( джерело ). Однак якщо вам потрібна більша гнучкість або потрібен більш чистий інтерфейс, ви також можете скопіювати статичні файли безпосередньо за допомогою my copy-webpack-plugin( npm , Github ). Для вашого staticдо buildприкладу:

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

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

11
Це набагато простіше, коли ви хочете скопіювати весь каталог (наприклад, статичний html та інші зображення котла)!
Арджун Мехта

6
Трюк, дякую :), відмовився від завантажувача файлів після декількох невдалих спроб змусити його виконати дуже просту команду. ваш плагін працював перший раз.
arcseldon

3
@Yan Плагін повторно копіює файли, якщо вони змінюються (dev-сервер або webpack --watch). Якщо це не копіювання для вас, будь ласка, подайте проблему.
kevlened

2
Я новачок у webpack, але мені важко зрозуміти, чому нам потрібно використовувати file-loader / url-loader / img-loader ... а не просто копіювати їх? Яку користь ми отримуємо від цього, скажімо, завантажувача файлів?
BreakDS

2
Оскільки ви автор плагіна. Немає кращого темпу, щоб задати це питання. Використовуючи плагін "copy-webpack-plugin" ... чи можу я фільтрувати файли з вихідного каталогу, щоб він копіював лише файл із певним розширенням файлу, наприклад. копіювати лише ".html"? З повагою
DevWL

56

Якщо ви хочете скопіювати статичні файли, ви можете використовувати завантажувач файлів таким чином:

для html-файлів:

в webpack.config.js:

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

у вашому js-файлі:

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

./static/ стосується вашого файлу js.

Можна зробити те ж саме із зображеннями чи будь-чим іншим. Контекст - це потужний метод дослідження !!


3
Я віддаю перевагу цьому методу над модулем copy-webpack-plugin. Крім того, мені вдалося змусити його працювати без використання "& context =. / App / static" у своєму конфігурації веб-пакету. Мені потрібен був лише рядок requ.context.
Дейв Лендрі

2
Я намагаюся це зробити, це здається чудовим, але для однієї невеликої проблеми, яку я отримую, це те, що він вводить мене index.htmlв підкаталог, який він створює під назвою _(підкреслення), що відбувається?
kris

2
Коли ви говорите "у своєму js-файлі", що ви маєте на увазі? Що робити, якщо у мене немає файлу JS?
evolutionxbox

абсолютно. Цей один рядок у сценарії введення, тобто main.jsімпортує все, що знаходиться в staticпапці:require.context("./static/", true, /^.*/);
Mario

2
Це акуратний злом, але якщо ви копіюєте занадто багато файлів, у вас не вистачить пам'яті.
Том

18

Однією з переваг, яку згаданий вище плагін copy-webpack приносить, що раніше не було пояснено, є те, що всі інші методи, згадані тут, як і раніше, зв'язують ресурси у ваші файли пакетів (і вимагають, щоб ви десь «вимагали» або «імпортували»). Якщо я просто хочу перемістити деякі зображення навколо або деякі шаблони шаблонів, я не хочу захаращувати свій файл пакета javascript з марними посиланнями на них, я просто хочу, щоб файли видавалися в потрібному місці. Я не знайшов іншого способу зробити це в webpack. Справді, це не те, для чого розроблявся веб-пакет, але це, безумовно, сучасний випадок використання. (@BreakDS Я сподіваюся, що це відповідає на ваше запитання - це лише користь, якщо ви цього хочете)


7

Наведені вище пропозиції хороші. Але щоб спробувати відповісти на ваше запитання безпосередньо, я б запропонував використовувати cpy-cliсценарій, визначений у вашому package.json.

Цей приклад розраховує nodeдесь на вашому шляху. Встановіть cpy-cliяк залежність від розвитку:

npm install --save-dev cpy-cli

Потім створіть пару файлів nodejs. Один зробити копію, а інший - відобразити галочку та повідомлення.

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;

Додати сценарій у package.json. Якщо припустити, що сценарії є в<project-root>/scripts/

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

Щоб запустити sript:

npm run copy


3
ОП хотів виконати переміщення файлу всередині webpack, не використовуючи сценарії npm?
Вільям С

Навіть коли OP хотів вирішити це все в webpack, можливо, він працює за допомогою webpack через npm, тому він міг би додати його до свого сценарію збирання, де запускається webpack
Піро каже: Відновити Моніку

5

Швидше за все, вам слід скористатися CopyWebpackPlugin, про який було сказано у відповіді з кевлем. Крім того, для таких файлів, як .html або .json, ви також можете використовувати raw-loader або json-loader. Встановіть його через npm install -D raw-loaderі тоді вам потрібно лише додати ще один завантажувач до нашого webpack.config.jsфайлу.

Подібно до:

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

Примітка. Перезавантажте веб-сервер dev-сервера, щоб зміни конфігурації набули чинності.

Тепер ви можете вимагати html-файлів, використовуючи відносні шляхи, це значно полегшує переміщення папок.

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

5

Спосіб завантаження статичного imagesта 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/'
          },
        }
    ]
}

Не забудьте встановити, file-loaderщоб це працювало.


Як ви обробляєте дублікати імен файлів? Або ще краще, ви знаєте будь-який спосіб зберегти оригінальний шлях у новому вихідному каталозі?
cantuket

У вашому проекті не повинно бути дублікату імені файлу з тим самим іменем розширення. Який сенс зберігати дублікати, хоча їх вміст однаковий? Якщо ні, то називайте їх по-різному відповідно до їх змісту. Хоча навіщо використовувати веб-пакет, якщо ви хочете зберегти свої речі в оригінальному шляху? Якщо ви хочете лише JS-переклад, то Вавілону повинно вистачити.
RegarBoy

1
Якщо ви впроваджуєте розробку на основі компонентів (одним з головних принципів якого є інкапсуляція, а конкретніше в даному випадку приховування інформації ) , то жодне з того, що ви згадали, не є доречним. тобто коли хтось додає новий компонент у програму, їм не потрібно перевіряти, чи є інше зображення з назвою, logo.pngі не повинно створювати тупих і "сподіваюся" унікальних імен файлів, щоб уникнути глобального зіткнення. З тієї ж причини ми використовуємо CSS-модулі .
cantuket

1
Щодо того, чому я хочу, щоб зображення підтримували початковий шлях та ім’я файлу; в основному налагодження, з тієї ж причини, що ви використовуєте вихідні карти, але також і SEO . Незважаючи на це, відповідь на моє запитання насправді була дуже простою… [path][name].[ext]і є достатня гнучкість, щоб змінити це для конкретного середовища або використовувати випадок… file-loader
cantuket

1
Коли ми говорили, ми реалізували варіант вашого прикладу, тож дякую за надання!
cantuket

3

Ви можете написати bash у своєму пакеті.json:

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

1
У Windows просто використовуйте xcopy замість cp:"build": "webpack && xcopy images dist\\images\\ /S /Y && xcopy css dist\\css\\ /S /Y"
SebaGra

7
Правильно, тож ваше рішення - мати різний сценарій для кожної ОС?
Мацей Гурбан

Так, для мене сценарій для кожної ОС прийнятний (це дійсно unix / non-unix, оскільки сценарій на Linux буде працювати на Дарвіні або іншому POSIX * nix)
Віктор Пудєєв

І той приклад Windows також не працюватиме з PowerShell як оболонкою за замовчуванням.
Джуліан Найт

На відміну від CopyWebpackPlugin, ця опція зберігає дати файлів. Випуск ОС може бути проблематичним для відкритого коду, але для менших команд легко управляти за допомогою Windows bash або обертання xcopy cp.bat.
Alien Technology

2

Я і тут застряг. copy-webpack-плагін працював на мене.

Однак "copy-webpack-plugin" у моєму випадку не знадобився (я дізнався пізніше).

webpack ігнорує
приклад кореневих шляхів

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

Отже, щоб зробити цю роботу без використання 'copy-webpack-plugin', використовуйте '~' у шляхах

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

'~' вказує webpack вважати 'images' модулем

Примітка: можливо, вам доведеться додати батьківський каталог директорій зображень у

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

Відвідайте https://vuejs-templates.github.io/webpack/static.html


2

Конфігураційний файл вебпакету (у вебпаку 2) дозволяє експортувати ланцюжок обіцянок, доки останній крок повертає об’єкт конфігурації вебпакету. Див. Документи про конфігурацію обіцянок . Звідти:

webpack тепер підтримує повернення Обіцянки з файлу конфігурації. Це дозволяє виконати обробку асинхронізації у вашому файлі конфігурації.

Ви можете створити просту рекурсивну функцію копіювання, яка копіює ваш файл, і лише після цього запускається веб-пакет. Наприклад:

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

1

скажемо, що всі ваші статичні активи знаходяться у папці "статично" на кореневому рівні, і ви хочете скопіювати їх у папку збірки, зберігаючи структуру підпапки, а потім у свій файл входу) просто поставте

//index.js or index.jsx

require.context("!!file?name=[path][name].[ext]&context=./static!../static/", true, /^\.\/.*\.*/);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.