วิธีคัดลอกไฟล์คงที่เพื่อสร้างไดเรกทอรีด้วย Webpack


330

ฉันพยายามที่จะย้ายจากไปGulp WebpackในGulpฉันมีงานที่คัดลอกไฟล์และโฟลเดอร์ทั้งหมดจาก/ คงที่ /โฟลเดอร์ไปที่/ สร้าง /โฟลเดอร์ วิธีการทำเช่นเดียวกันกับWebpack? ฉันต้องการปลั๊กอินไหม


2
อึกดีที่จะเข้าใจ เพียงโทร webpack จาก gulpfile.js หากต้องการ
Baryon Lee

หากคุณใช้ Laravel Mix คุณสามารถใช้laravel.com/docs/5.8/mix#copying-files-and-directoriesได้
Ryan

คำตอบ:


179

คุณไม่จำเป็นต้องคัดลอกสิ่งต่าง ๆ webpack ทำงานต่างจากอึก 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'

โดยทั่วไปแล้ว loader จะถูกนำไปใช้ผ่านการกำหนดค่า webpack:

// webpack.config.js

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

แน่นอนคุณต้องติดตั้งตัวโหลดไฟล์ก่อนเพื่อให้สามารถใช้งานได้


42
" แน่นอนคุณต้องติดตั้งไฟล์โหลดแรกที่จะทำให้งานนี้. " เชื่อมโยงไปดังกล่าว "แฟ้ม-loader" ที่นี่ และนี่คือวิธีการติดตั้งและใช้งาน
เนท

21
คุณยังคงมีปัญหาของไฟล์ HTML และการอ้างอิงทั้งหมดในไฟล์เหล่านั้นไม่ได้โหลด
kilianc

126
ใช่ถ้าคุณต้องการอยู่ในนรกของปลั๊กอิน webpack คุณสามารถใช้ file-loader, css-loader, style-loader, url-loader, ... และจากนั้นคุณสามารถมีเวลามากในการกำหนดค่าแบบที่คุณต้องการ และ googling และ non-sleep :) หรือคุณสามารถใช้ copy-webpack-plugin และทำงานให้เสร็จ ...
Kamil Tomšík

11
@ KamilTomšíkดังนั้นคำแนะนำของคุณคือเราควรใช้ปลั๊กอิน webpack เพื่อหลีกเลี่ยงปลั๊กอิน webpack หรือไม่ (ล้อเล่นฉันได้คะแนนของคุณแล้ว)
Konrad Viltersten

12
ตกลงส่วนใหญ่ของรูปภาพทั้งหมดอยู่ใน css และ html ดังนั้นฉันควรต้องการรูปภาพทั้งหมดเหล่านี้ในไฟล์ JS ของฉันโดยใช้ require ('img.png'); จะทำให้มันทำงานกับตัวโหลดไฟล์ได้อย่างไร นั่นเป็นสิ่งที่ค่อนข้างบ้า
Rantiev

580

เนื้อหาที่ต้องการโดยใช้โมดูลตัวโหลดไฟล์เป็นวิธีที่ webpack ตั้งใจจะใช้ ( แหล่งที่มา ) อย่างไรก็ตามหากคุณต้องการความยืดหยุ่นที่มากขึ้นหรือต้องการอินเทอร์เฟซที่สะอาดกว่าคุณสามารถคัดลอกไฟล์คงที่ได้โดยตรงโดยใช้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 คงที่และภาพสำเร็จรูปอื่น ๆ )!
Arjun Mehta

6
ทำตามคำแนะนำได้ไหมขอบคุณ :) ยอมแพ้กับตัวโหลดไฟล์หลังจากที่หลายครั้งล้มเหลวในการพยายามทำให้มันใช้คำสั่งง่าย ๆ ปลั๊กอินของคุณทำงานเป็นครั้งแรก
arcseldon

3
@Yan ปลั๊กอินทำการคัดลอกไฟล์อีกครั้งหากมีการเปลี่ยนแปลง (dev-server หรือ 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" ในการกำหนดค่า webpack ของฉัน ฉันต้องการเฉพาะบรรทัด require.context
Dave Landry

2
ฉันกำลังลองสิ่งนี้มันดูดี แต่สำหรับปัญหาเล็ก ๆ น้อย ๆ ที่ฉันได้รับซึ่งก็คือการที่ฉันกำลังวางindex.htmlไดเรกทอรีย่อยที่กำลังสร้างชื่อ_(ขีดล่าง) เกิดอะไรขึ้น
kris

2
เมื่อคุณพูดว่า "in js file" คุณหมายถึงอะไร ถ้าฉันไม่มีไฟล์ JS ล่ะ?
evolutionxbox

อย่างแน่นอน บรรทัดหนึ่งในสคริปต์รายการmain.jsนี้คือการนำเข้าทุกอย่างภายในstaticโฟลเดอร์:require.context("./static/", true, /^.*/);
Mario Mario

2
นี่เป็นแฮ็คที่เรียบร้อย แต่ถ้าคุณคัดลอกไฟล์มากเกินไปคุณจะมีหน่วยความจำไม่เพียงพอ
ทอม

18

ข้อดีอย่างหนึ่งที่copy-webpack-pluginดังกล่าวนำมาซึ่งยังไม่ได้อธิบายมาก่อนคือวิธีการทั้งหมดที่กล่าวถึงในที่นี้ยังคงรวมทรัพยากรลงในไฟล์บันเดิลของคุณ (และต้องการให้คุณ "ต้องการ" หรือ "นำเข้า" ที่อื่น) ถ้าฉันต้องการย้ายรูปภาพไปรอบ ๆ หรือเทมเพลตเทมเพลตฉันไม่ต้องการให้ไฟล์ javascript บันเดิลของฉันยุ่งเหยิงโดยไม่มีการอ้างอิงถึงพวกเขาฉันแค่ต้องการให้ไฟล์ที่ถูกปล่อยออกมาถูกที่แล้ว ฉันไม่พบวิธีอื่นในการทำ webpack เป็นที่ยอมรับว่าไม่ใช่สิ่งที่ออกแบบมาสำหรับ webpack แต่เป็นกรณีการใช้งานในปัจจุบัน (@BreakDS ฉันหวังว่านี่จะตอบคำถามของคุณ - มันจะเป็นประโยชน์ถ้าคุณต้องการ)


7

คำแนะนำข้างต้นเป็นสิ่งที่ดี แต่การที่จะพยายามที่จะตอบคำถามของคุณโดยตรงผมขอแนะนำให้ใช้ในสคริปต์ที่กำหนดไว้ในของคุณcpy-clipackage.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
OP ต้องการทำให้ไฟล์เคลื่อนไหวภายใน webpack ไม่ใช่ใช้สคริปต์ npm หรือไม่
วิลเลียมเอส

แม้ว่า OP ต้องการแก้ปัญหานี้ภายใน webpack ก็เป็นไปได้ว่าเขากำลังเรียกใช้ webpack ถึง npm ดังนั้นเขาจึงสามารถเพิ่มสคริปต์สร้างของเขาที่ webpack ทำงาน
Piro กล่าว Reinstate Monica

5

เป็นไปได้มากว่าคุณควรใช้ CopyWebpackPlugin ซึ่งถูกกล่าวถึงในคำตอบของ เป็นทางเลือกสำหรับไฟล์บางประเภทเช่น. 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ให้ใช้งานได้


คุณจัดการกับชื่อไฟล์ซ้ำได้อย่างไร หรือดีกว่าคุณรู้วิธีการรักษาเส้นทางเดิมในไดเรกทอรีออกใหม่หรือไม่
cantuket

คุณไม่ควรมีชื่อไฟล์ซ้ำกับชื่อนามสกุลเดียวกันในโครงการของคุณ อะไรคือจุดที่ทำให้ซ้ำซ้อนแม้ว่าเนื้อหาของพวกเขาจะเหมือนกัน? ถ้าไม่เช่นนั้นให้ตั้งชื่อพวกเขาแตกต่างกันไปตามเนื้อหาของพวกเขา แม้ว่าคุณจะใช้เว็บแพคทำไมถ้าคุณต้องการเก็บสิ่งต่าง ๆ ในเส้นทางเดิม หากคุณต้องการการแปล JS เพียงอย่างเดียว Babel น่าจะเพียงพอ
RegarBoy

1
หากคุณกำลังใช้การพัฒนาโดยใช้องค์ประกอบ(หนึ่งในหลักการหลักที่มีการห่อหุ้มและเฉพาะเจาะจงมากขึ้นในการซ่อนข้อมูลกรณีนี้) แสดงว่าคุณไม่ได้กล่าวถึงสิ่งใดเลย เช่นเมื่อมีคนเพิ่มองค์ประกอบใหม่ให้กับโปรแกรมพวกเขาไม่จำเป็นต้องตรวจสอบว่ามีชื่ออื่นlogo.pngหรือไม่และพวกเขาต้องสร้างชื่อที่ไม่เหมาะสมและ "หวังว่า" ชื่อไฟล์ที่ไม่ซ้ำกันเพื่อหลีกเลี่ยงการชนกันทั่วโลก ด้วยเหตุผลเดียวกันเราใช้CSS โมดูล
cantuket

1
เหตุใดฉันจึงต้องการให้รูปภาพต่าง ๆ เพื่อรักษาเส้นทางและชื่อไฟล์ดั้งเดิม แก้จุดบกพร่องส่วนใหญ่เป็นเหตุผลเดียวกับที่คุณต้องการใช้ sourcemaps แต่ยังSEO โดยไม่คำนึงถึงคำตอบสำหรับคำถามของฉันนั้นง่ายมากจริง ๆ ... [path][name].[ext]และมีความยืดหยุ่นมากมายในการปรับเปลี่ยนให้เหมาะสมกับสภาพแวดล้อมที่เฉพาะเจาะจงหรือใช้กรณี ... file-loader
cantuket

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
ใช่แล้วทางออกของคุณคือมีสคริปต์ที่แตกต่างกันสำหรับแต่ละระบบปฏิบัติการ
Maciej Gurban

ใช่สำหรับฉันสคริปต์สำหรับแต่ละระบบปฏิบัติการเป็นที่ยอมรับ (มันเป็น unix / non-unix จริง ๆ เนื่องจากสคริปต์บน linux จะทำงานบน Darwin หรือ POSIX * ระวังอื่น)
Victor Pudeyev

และตัวอย่างของ Windows จะไม่ทำงานกับ PowerShell เป็นเชลล์เริ่มต้นเช่นกัน
Julian Knight

ไม่เหมือนกับ CopyWebpackPlugin ตัวเลือกนี้จะเก็บวันที่ของไฟล์ ปัญหาของระบบปฏิบัติการอาจเป็นปัญหาสำหรับโอเพ่นซอร์ส แต่สำหรับทีมเล็ก ๆ นั้นสามารถจัดการกับ Windows ทุบตีหรือปิด xcopy ด้วย cp.bat ได้อย่างง่ายดาย
เทคโนโลยีของคนต่างด้าว

2

ฉันติดอยู่ที่นี่เช่นกัน copy-webpack-plugin ใช้งานได้สำหรับฉัน

อย่างไรก็ตาม 'copy-webpack-plugin' ไม่จำเป็นในกรณีของฉัน (ฉันเรียนรู้ในภายหลัง)

webpack ไม่สนใจ
ตัวอย่างเส้นทางของรูท

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

ดังนั้นเพื่อให้สามารถทำงานได้โดยไม่ต้องใช้ 'copy-webpack-plugin' use '~' ในพา ธ

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

'~' บอกให้ webpack พิจารณา 'images' เป็นโมดูล

หมายเหตุ: คุณอาจต้องเพิ่มไดเรกทอรีหลักของไดเรกทอรีรูปภาพใน

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

เยี่ยมชมhttps://vuejs-templates.github.io/webpack/static.html


2

ไฟล์กำหนดค่า webpack (ใน webpack 2) ให้คุณส่งออกเครือสัญญาได้ตราบใดที่ขั้นตอนสุดท้ายส่งคืนวัตถุกำหนดค่า webpack ดูเอกสารการกำหนดค่าสัญญา จากที่นั่น:

ตอนนี้ webpack สนับสนุนการคืนสัญญาจากไฟล์การกำหนดค่า สิ่งนี้อนุญาตให้ทำการประมวลผล async ในไฟล์กำหนดค่าของคุณ

คุณสามารถสร้างฟังก์ชั่นการคัดลอกซ้ำแบบง่ายๆที่คัดลอกไฟล์ของคุณและหลังจากนั้นจะทริกเกอร์ 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, /^\.\/.*\.*/);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.