Как скопировать статические файлы для создания каталога с помощью Webpack?


331

Я пытаюсь перейти от Gulpк Webpack. У Gulpменя есть задача, которая копирует все файлы и папки из / static / folder в / build / folder. Как сделать то же самое с Webpack? Нужен ли мне какой-нибудь плагин?


2
Глоток это здорово, чтобы понять. просто позвоните в вебпак с gulpfile.js, если хотите
Барион Ли

Если вы используете Laravel Mix, доступен laravel.com/docs/5.8/mix#copying-files-and-directories .
Райан

Ответы:


179

Вам не нужно копировать вещи, веб-пакет работает иначе, чем gulp. 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:

// webpack.config.js

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

Конечно, вам нужно сначала установить загрузчик файлов, чтобы это работало.


42
« Конечно, сначала вам нужно установить загрузчик файлов. » Ссылка на вышеупомянутый «загрузчик файлов» здесь . А вот как это установить и использовать.
Нэйт

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

126
да, если вы хотите попасть в ад плагинов webpack, вы можете использовать файл-загрузчик, css-загрузчик, style-загрузчик, url-загрузчик, ... и тогда вы сможете отлично настроить его так, как вам нужно и гуглите и не спите :) или вы можете использовать copy-webpack-plugin и выполнить свою работу ...
Камил Томшик

11
@ KamilTomšík Итак, вы рекомендуете использовать плагин веб-пакетов, чтобы избежать плагинов веб-пакетов? (Шучу. Я понял твою точку зрения.)
Конрад Вилтерстен

12
Хорошо, большая часть всех изображений в CSS и HTML. Поэтому я должен требовать все эти изображения в моих файлах JS, используя require ('img.png'); заставить его работать с этим загрузчиком файлов? Это довольно сумасшедшая вещь.
Рантьев

581

Требование ресурсов с помощью модуля загрузчика файлов - это способ использования веб-пакета ( источник ). Однако, если вам нужна большая гибкость или более чистый интерфейс, вы также можете копировать статические файлы напрямую, используя 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-server или webpack --watch). Если это не копирование для вас, пожалуйста, сообщите о проблеме.
Кевленед

2
Я новичок в Webpack, но мне трудно понять, почему мы должны использовать файл-загрузчик / url-loader / img-loader ... вместо того, чтобы просто копировать их? Какую пользу мы получим, скажем, от загрузчика файлов?
BreakDS

2
Так как вы автор плагина. Нет лучшего способа задать этот вопрос. Используя плагин "copy-webpack-plugin" ... я могу отфильтровать файлы из исходного каталога, чтобы он копировал только файлы с определенным расширением ex. копировать только ".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» в моей конфигурации веб-пакета. Мне нужна была только строка require.context.
Дейв Лэндри,

2
Я пытаюсь это, это кажется великолепным, но для одной маленькой проблемы, которую я получаю, это то, что она помещает мою index.htmlпапку в подкаталог, который она создает, называется _(подчеркивание), что происходит?
Крис

2
Когда вы говорите "в вашем файле JS", что вы имеете в виду? Что делать, если у меня нет файла JS?
evolutionxbox

абсолютно. Эта одна строка в скрипте ввода, т.е. main.jsимпортирует все в staticпапке:require.context("./static/", true, /^.*/);
Mario

2
Это аккуратный хак, но если вы копируете слишком много файлов, вам не хватит памяти.
Том

18

Одно преимущество, которое приносит вышеупомянутый copy-webpack-plugin , которое не было объяснено ранее, состоит в том, что все другие методы, упомянутые здесь, все еще объединяют ресурсы в ваши файлы комплекта (и требуют, чтобы вы «требовали» или «импортировали» их где-то). Если я просто хочу переместить некоторые изображения или некоторые шаблоны, я не хочу загромождать свой файл комплекта javascript бесполезными ссылками на них, я просто хочу, чтобы файлы выводились в нужном месте. Я не нашел другого способа сделать это в веб-пакете. По общему признанию это не то, для чего первоначально был разработан веб-пакет, но это определенно текущий случай использования. (@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",
...

Чтобы запустить скрипт:

npm run copy


3
ОП хотел выполнить перемещение файла внутри веб-пакета, не используя сценарии npm?
Уильям С.

Даже когда ОП хотел решить эту проблему внутри веб-пакета, возможно, он запускает веб-пакет через npm, поэтому он может добавить его в свой сценарий сборки, в котором запускается веб-пакет
Пиро говорит Reinstate Monica

5

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

Подобно:

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

Примечание. Перезапустите webpack-dev-server, чтобы изменения в конфигурации вступили в силу.

И теперь вы можете запрашивать 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чтобы это работало.


Как вы обрабатываете дубликаты имен файлов? Или, что еще лучше, вы знаете, как сохранить исходный путь в новом каталоге вывода?
канткет

В вашем проекте не должно быть повторяющегося имени файла с таким же расширением. Какой смысл хранить дубликаты, если их содержание идентично? Если нет, то называйте их по-разному в зависимости от их содержания. Хотя зачем вам использовать webpack, если вы хотите сохранить свои вещи в оригинальном пути? Если вы хотите только перевод JS, то Бабел должно быть достаточно.
RegarBoy

1
Если вы реализуете компонентно-ориентированную разработку (одним из основных принципов которой является инкапсуляция и, более конкретно, в данном случае сокрытие информации ) , то ничего из того, что вы упомянули, не подходит. То есть, когда кто-то добавляет новый компонент в программу, ему не нужно проверять, не названо ли другое изображение, logo.pngи не нужно создавать тупое и, мы надеемся, уникальное имя файла, чтобы избежать глобальной коллизии. По той же причине мы используем модули CSS .
канткет

1
Что касается того, почему я хочу, чтобы изображения сохраняли исходный путь и имя файла; в основном отладка, по той же причине, по которой вы будете использовать исходные карты, но также и SEO . Несмотря на это, ответ на мой вопрос был на самом деле очень простым ... [path][name].[ext]и была предусмотрена
большая

1
При этом мы реализовали вариант вашего примера, так что спасибо за предоставление!
cantuket

3

Вы можете написать bash в вашем package.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 будет работать на Darwin или другом POSIX * nix)
Виктор Пудеев

И этот пример Windows не будет работать с PowerShell в качестве оболочки по умолчанию.
Джулиан Найт

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

2

Я тоже застрял здесь. copy-webpack-plugin работал для меня.

Однако в моем случае «copy-webpack-plugin» не был необходим (я узнал позже).

webpack игнорирует
пример корневых путей

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

Следовательно, чтобы сделать это без использования 'copy-webpack-plugin', используйте '~' в путях

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

«~» указывает веб-пакету рассматривать «изображения» как модуль

примечание: вам может понадобиться добавить родительский каталог к ​​каталогу изображений в

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

Посетите https://vuejs-templates.github.io/webpack/static.html.


2

Файл конфигурации веб-пакета (в веб-пакете 2) позволяет экспортировать цепочку обещаний, если последний шаг возвращает объект конфигурации веб-пакета. Смотрите документацию по конфигурации обещаний . Оттуда:

Теперь webpack поддерживает возврат Promise из файла конфигурации. Это позволяет выполнять асинхронную обработку в вашем файле конфигурации.

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

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

1

скажем, все ваши статические ресурсы находятся в папке «static» на корневом уровне, и вы хотите скопировать их в папку сборки, сохраняя структуру подпапки, а затем в ваш файл ввода) просто поместите

//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.