Làm cách nào để sao chép tệp tĩnh để xây dựng thư mục với Webpack?


330

Tôi đang cố gắng chuyển từ Gulpsang Webpack. Trong Gulptôi có nhiệm vụ sao chép tất cả các tệp và thư mục từ / static / thư mục sang / build / thư mục. Làm thế nào để làm điều tương tự với Webpack? Tôi có cần một số plugin không?


2
Gulp là tuyệt vời để hiểu. chỉ cần gọi webpack từ gulpfile.js nếu bạn muốn
Baryon Lee

Nếu bạn đang sử dụng Laravel Mix, laravel.com/docs/5.8/mix#copying-files-and-directories có sẵn.
Ryan

Câu trả lời:


179

Bạn không cần phải sao chép mọi thứ xung quanh, webpack hoạt động khác với gulp. Webpack là một gói mô-đun và mọi thứ bạn tham chiếu trong tệp của bạn sẽ được bao gồm. Bạn chỉ cần xác định một trình tải cho điều đó.

Vì vậy, nếu bạn viết:

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

Trước tiên, Webpack sẽ cố phân tích tệp được tham chiếu là JavaScript (vì đó là mặc định). Tất nhiên, điều đó sẽ thất bại. Đó là lý do tại sao bạn cần chỉ định một trình tải cho loại tệp đó. Ví dụ, tệp - hoặc trình tải url lấy tệp được tham chiếu, đặt nó vào thư mục đầu ra của webpack (cần có buildtrong trường hợp của bạn) và trả về url được băm cho tệp đó.

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

Thông thường các trình tải được áp dụng thông qua cấu hình webpack:

// webpack.config.js

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

Tất nhiên bạn cần cài đặt trình tải tập tin trước để thực hiện công việc này.


42
" Tất nhiên trước tiên bạn cần cài đặt trình tải tệp để thực hiện công việc này. " Liên kết đến "trình tải tệp" đã nói ở trên . Và đây là cách cài đặt và sử dụng nó.
Nate

21
Bạn vẫn gặp sự cố về tệp HTML và tất cả các tham chiếu trong đó không được tải.
kilianc

125
vâng, nếu bạn muốn tìm hiểu các plugin webpack, bạn có thể sử dụng trình tải tệp, trình tải css, trình tải kiểu, trình tải url, ... và sau đó bạn có thể có thời gian tuyệt vời để định cấu hình theo cách bạn cần và googling và không ngủ :) hoặc bạn có thể sử dụng plugin-webpack-plugin và hoàn thành công việc của mình ...
Kamil Tomšík

11
@ KamilTomšík Vì vậy, đề xuất của bạn là chúng ta nên sử dụng plugin webpack để tránh các plugin webpack? (Đùa thôi. Tôi hiểu ý của bạn.)
Konrad Viltersten

12
Ok, hầu hết các phần của tất cả các hình ảnh đều có trong css và html. Vì vậy, tôi nên yêu cầu tất cả những hình ảnh này trong các tệp JS của mình bằng cách sử dụng yêu cầu ('img.png'); để làm cho nó hoạt động với trình tải tập tin đó? Đó là điều khá điên rồ.
Rantiev

579

Yêu cầu tài sản bằng cách sử dụng mô-đun trình tải tệp là cách webpack được sử dụng ( nguồn ). Tuy nhiên, nếu bạn cần linh hoạt hơn hoặc muốn có giao diện sạch hơn, bạn cũng có thể sao chép trực tiếp các tệp tĩnh bằng cách sử dụng copy-webpack-plugin( npm , Github ) của tôi. Để tiện staticcho buildví dụ:

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

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

11
Điều này đơn giản hơn nhiều khi bạn muốn sao chép toàn bộ thư mục (ví dụ: html tĩnh và các hình ảnh soạn sẵn khác)!
Arjun Mehta

6
Đã lừa, cảm ơn bạn :) đã từ bỏ trình tải tập tin sau nhiều lần thất bại để làm cho nó thực hiện một lệnh rất đơn giản. Plugin của bạn hoạt động lần đầu tiên.
arcseldon

3
@Yan Plugin không sao chép lại các tệp nếu chúng thay đổi (dev-server hoặc webpack --watch). Nếu nó không sao chép cho bạn, xin vui lòng gửi một vấn đề.
kevlened

2
Tôi chưa quen với webpack, nhưng tôi gặp khó khăn trong việc hiểu tại sao chúng ta cần sử dụng trình tải tệp / url-loader / img-loader ... thay vì chỉ sao chép chúng? Lợi ích mà chúng ta có được khi làm điều này với, nói, trình tải tệp là gì?
BreakDS

2
Vì bạn là tác giả plugin. Không có tốc độ tốt hơn để đặt câu hỏi này. Sử dụng plugin "copy-webpack-plugin" ... tôi có thể lọc các tệp từ thư mục nguồn để nó chỉ sao chép tệp với phần mở rộng tệp nhất định. chỉ sao chép ".html"? Trân trọng
DevWL

56

Nếu bạn muốn sao chép các tệp tĩnh của mình, bạn có thể sử dụng trình tải tệp theo cách này:

cho các tệp html:

trong webpack.config.js:

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

trong tập tin js của bạn:

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

./static/ liên quan đến vị trí tệp js của bạn.

Bạn có thể làm tương tự với hình ảnh hoặc bất cứ điều gì. Bối cảnh là một phương pháp mạnh mẽ để khám phá !!


3
Tôi thích phương pháp này hơn mô-đun copy-webpack-plugin. Ngoài ra, tôi có thể làm cho nó hoạt động mà không cần sử dụng "& bối cảnh =. / App / static" trong cấu hình gói webpack của tôi. Tôi chỉ cần dòng request.context.
Dave Landry

2
Tôi đang thử điều này, nó có vẻ tuyệt vời nhưng đối với một vấn đề nhỏ mà tôi gặp phải, đó là việc đưa tôi index.htmlvào một thư mục con mà nó đang tạo ra được gọi là _(gạch dưới), chuyện gì đang xảy ra?
kris

2
Khi bạn nói "trong tập tin js của bạn", bạn có ý gì? Nếu tôi không có tệp JS thì sao?
Evolutionxbox

chắc chắn rồi. Dòng này trong tập lệnh nhập, tức main.jslà đang nhập mọi thứ trong staticthư mục:require.context("./static/", true, /^.*/);
Mario

2
Đây là một bản hack gọn gàng nhưng nếu bạn sao chép quá nhiều tệp qua thì bạn sẽ hết bộ nhớ.
Tom

18

Một lợi thế mà plugin-webpack-plugin đã nói ở trên chưa được giải thích trước đó là tất cả các phương pháp khác được đề cập ở đây vẫn gói tài nguyên vào các tệp bó của bạn (và yêu cầu bạn "yêu cầu" hoặc "nhập" chúng ở đâu đó). Nếu tôi chỉ muốn di chuyển một số hình ảnh xung quanh hoặc một số phần mẫu, tôi không muốn làm lộn xộn tệp gói javascript của mình với các tham chiếu vô dụng đến chúng, tôi chỉ muốn các tệp được phát ra ở đúng nơi. Tôi không tìm thấy cách nào khác để làm điều này trong webpack. Phải thừa nhận rằng đó không phải là gói web ban đầu được thiết kế cho, nhưng đây chắc chắn là trường hợp sử dụng hiện tại. (@BreakDS Tôi hy vọng điều này trả lời câu hỏi của bạn - nó chỉ là một lợi ích nếu bạn muốn nó)


7

Trên đề xuất là tốt. Nhưng để cố gắng trả lời trực tiếp câu hỏi của bạn, tôi khuyên bạn nên sử dụng cpy-clitập lệnh được xác định trong package.json.

Ví dụ này mong đợi nodeở đâu đó trên con đường của bạn. Cài đặt cpy-clinhư một phụ thuộc phát triển:

npm install --save-dev cpy-cli

Sau đó tạo một vài tập tin nodejs. Một để làm bản sao và cái còn lại để hiển thị một dấu kiểm và thông báo.

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;

Thêm tập lệnh vào package.json. Giả sử tập lệnh là trong<project-root>/scripts/

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

Để chạy sript:

npm run copy


3
OP muốn hoàn thành tập tin di chuyển bên trong gói web, không sử dụng tập lệnh npm?
William S

Ngay cả khi OP muốn giải quyết vấn đề này bên trong webpack, có thể anh ta đang chạy webpack qua npm, vì vậy anh ta có thể thêm nó vào tập lệnh xây dựng của mình nơi chạy webpack
Piro nói Rebstate Monica

5

Nhiều khả năng bạn nên sử dụng CopyWebpackPlugin đã được đề cập trong câu trả lời kevlened. Thay thế cho một số loại tệp như .html hoặc .json, bạn cũng có thể sử dụng trình tải thô hoặc trình tải json. Cài đặt nó qua npm install -D raw-loadervà sau đó những gì bạn chỉ cần làm là thêm một trình tải khác vào webpack.config.jstệp của chúng tôi .

Giống:

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

Lưu ý: Khởi động lại webpack-dev-server để mọi thay đổi cấu hình có hiệu lực.

Và bây giờ bạn có thể yêu cầu các tệp html bằng cách sử dụng các đường dẫn tương đối, điều này giúp việc di chuyển các thư mục xung quanh dễ dàng hơn nhiều.

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

5

Cách tôi tải tĩnh imagesfonts:

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/'
          },
        }
    ]
}

Đừng quên cài đặt file-loaderđể làm việc đó.


Làm thế nào để bạn xử lý tên tập tin trùng lặp? Hoặc tốt hơn, bạn có biết cách nào để giữ đường dẫn gốc trong thư mục đầu ra mới không?
cantologne

Bạn không nên có tên tệp trùng lặp với cùng tên mở rộng trong dự án của mình. Điểm gì để giữ các bản sao mặc dù nếu nội dung của chúng là giống hệt nhau? Nếu không, sau đó đặt tên khác nhau theo nội dung của họ. Mặc dù tại sao bạn sẽ sử dụng webpack nếu bạn muốn giữ mọi thứ trong đường dẫn ban đầu? Nếu bạn chỉ muốn dịch thuật thì Babel là đủ.
RegarBoy

1
Nếu bạn đang thực hiện phát triển dựa trên thành phần (một trong những nguyên tắc chính là đóng gói và cụ thể hơn trong trường hợp này là ẩn thông tin ) , thì không có điều gì bạn đề cập là thích hợp. tức là khi ai đó thêm một thành phần mới vào chương trình, họ không cần phải kiểm tra xem có hình ảnh nào khác được đặt tên logo.pnghay không và phải tạo một tên tập tin duy nhất và "hy vọng" để tránh xung đột toàn cầu. Cùng một lý do chúng tôi sử dụng các Mô-đun CSS .
cantologne

1
Về lý do tại sao tôi muốn hình ảnh duy trì đường dẫn và tên tệp gốc; gỡ lỗi chủ yếu, cùng một lý do bạn sử dụng sourcemaps, mà còn SEO . Bất kể, câu trả lời cho câu hỏi của tôi thực sự rất đơn giản ... [path][name].[ext]và có rất nhiều sự linh hoạt được cung cấp để sửa đổi điều này cho môi trường cụ thể hoặc trường hợp sử dụng ... trình tải tệp
cantologne

1
Điều đó được nói rằng chúng tôi đã thực hiện một biến thể của ví dụ của bạn vì vậy cảm ơn bạn đã cung cấp!
cantologne

3

Bạn có thể viết bash trong gói.json của bạn:

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

1
Trong Windows, chỉ cần sử dụng xcopy thay vì cp:"build": "webpack && xcopy images dist\\images\\ /S /Y && xcopy css dist\\css\\ /S /Y"
SebaGra

7
Phải, vậy giải pháp của bạn là có một tập lệnh khác nhau cho mỗi HĐH?
Maciej Gurban

Có, đối với tôi, một tập lệnh cho mỗi HĐH có thể chấp nhận được (nó thực sự là unix / non-unix, vì một tập lệnh trên linux sẽ chạy trên Darwin hoặc một POSIX * nix khác)
Victor Pudeyev

Và ví dụ Windows đó sẽ không hoạt động với PowerShell làm vỏ mặc định.
Julian Knight

Không giống như CopyWebpackPlugin, tùy chọn này giữ ngày của tệp. Vấn đề hệ điều hành có thể có vấn đề đối với nguồn mở, nhưng đối với các nhóm nhỏ hơn có thể dễ dàng quản lý bằng Windows bash hoặc gói xcopy bằng cp.bat.
Công nghệ ngoài hành tinh

2

Tôi cũng bị kẹt ở đây. copy-webpack-plugin làm việc cho tôi.

Tuy nhiên, 'copy-webpack-plugin' không cần thiết trong trường hợp của tôi (tôi đã học sau).

webpack bỏ qua
ví dụ đường dẫn gốc

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

Do đó, để làm cho công việc này hoạt động mà không cần sử dụng 'copy-webpack-plugin', hãy sử dụng '~' trong đường dẫn

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

'~' yêu cầu webpack coi 'hình ảnh' là một mô-đun

lưu ý: bạn có thể phải thêm thư mục mẹ của thư mục hình ảnh trong

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

Truy cập https://vuejs-temsheet.github.io/webpack/static.html


2

Tệp cấu hình webpack (trong webpack 2) cho phép bạn xuất chuỗi hứa hẹn, miễn là bước cuối cùng trả về một đối tượng cấu hình webpack. Xem tài liệu cấu hình hứa hẹn . Từ đó:

webpack hiện hỗ trợ trả lại một Promise từ tệp cấu hình. Điều này cho phép thực hiện xử lý async trong tệp cấu hình của bạn.

Bạn có thể tạo một chức năng sao chép đệ quy đơn giản sao chép tệp của mình và chỉ sau khi kích hoạt gói web. Ví dụ:

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

1

giả sử tất cả các tài sản tĩnh của bạn nằm trong một thư mục "tĩnh" ở cấp gốc và bạn muốn sao chép chúng vào thư mục xây dựng để duy trì cấu trúc của thư mục con, sau đó trong tệp nhập của bạn) chỉ cần đặt

//index.js or index.jsx

require.context("!!file?name=[path][name].[ext]&context=./static!../static/", true, /^\.\/.*\.*/);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.