我正在尝试从 移动Gulp
到Webpack
. 在Gulp
我的任务中,将所有文件和文件夹从/static/文件夹复制到/build/文件夹。如何做同样的事情Webpack
?我需要一些插件吗?
12 回答
使用 file-loader 模块请求资产是 webpack 的预期使用方式(source)。但是,如果您需要更大的灵活性或想要更简洁的界面,您也可以直接使用 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({
patterns: [
{ from: 'static' }
]
})
]
};
兼容性说明:如果您使用的是旧版本的 webpack,例如webpack@4.x.x
,请使用copy-webpack-plugin@6.x.x
. 否则使用最新的。
你不需要到处复制东西,webpack 的工作方式与 gulp 不同。Webpack 是一个模块捆绑器,您在文件中引用的所有内容都将包含在内。您只需要为此指定一个加载程序。
所以如果你写:
var myImage = require("./static/myImage.jpg");
Webpack 将首先尝试将引用的文件解析为 JavaScript(因为这是默认设置)。当然,那会失败。这就是您需要为该文件类型指定加载程序的原因。该文件- 或url-loader例如获取引用的文件,将其放入 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" }
]
}
};
当然,您需要先安装文件加载器才能完成这项工作。
如果要复制静态文件,可以通过以下方式使用文件加载器:
对于 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 文件所在的位置。
你可以对图像或其他东西做同样的事情。上下文是一种强大的探索方法!
前面提到的copy-webpack-plugin带来的一个之前没有解释过的优点是,这里提到的所有其他方法仍然将资源捆绑到你的包文件中(并要求你在某处“要求”或“导入”它们)。如果我只想移动一些图像或一些模板部分,我不想用对它们的无用引用来弄乱我的 javascript 包文件,我只希望在正确的位置发出文件。我还没有在 webpack 中找到任何其他方法来做到这一点。诚然,这不是 webpack 最初设计的目的,但它绝对是当前的用例。(@BreakDS 我希望这能回答你的问题——如果你想要的话,这只是一个好处)
Webpack 5 添加了资产模块,这些模块本质上是普通文件加载器的替代品。我复制了以下文档的相关部分:
asset/resource
发出一个单独的文件并导出 URL。以前可以通过使用file-loader
.asset/inline
导出资产的数据 URI。以前可以通过使用url-loader
.asset/source
导出资产的源代码。以前可以通过使用raw-loader
.asset
自动在导出数据 URI 和发出单独文件之间进行选择。以前可以通过使用url-loader
资产大小限制来实现。
你可以让你的配置看起来像这样:
// webpack.config.js
module.exports = {
...
module: {
rules: [
{
test: /\.(jpe?g|gif|png|svg|woff|ttf|wav|mp3)$/,
type: "asset/resource"
}
]
}
};
您可以处理如何使用模板路径复制文件。对于所有资产的默认模板,您可以执行以下操作:
// webpack.config.js
module.exports = {
...
output: {
...
assetModuleFilename: '[path][name].[hash][ext][query]'
}
}
对于一组特定的资产,您需要这样做:
// webpack.config.js
module.exports = {
...
module: {
rules: [
{
test: /\.(jpe?g|gif|png|svg|woff|ttf|wav|mp3)$/,
type: "asset/resource"
generator: {
filename: '[path][name].[hash][ext][query]'
}
}
]
}
};
提供的模板将导致文件名看起来像build/images/img.151cfcfa1bd74779aadb.png
. 将模板修改为您的用例。
以上建议都不错。但是要尝试直接回答您的问题,我建议cpy-cli
在您的package.json
.
这个例子期望node
在你的路径上的某个地方。cpy-cli
作为开发依赖安装:
npm install --save-dev cpy-cli
然后创建几个 nodejs 文件。一个用于复制,另一个用于显示复选标记和消息。
复制.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');
}
复选标记.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
我加载静态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
以使其正常工作。
您很可能应该使用 kevlened 答案中提到的 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')
您可以在 package.json 中编写 bash:
# package.json
{
"name": ...,
"version": ...,
"scripts": {
"build": "NODE_ENV=production npm run webpack && cp -v <this> <that> && echo ok",
...
}
}
我也被困在这里。copy-webpack-plugin 为我工作。
但是,在我的情况下,“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'
]
}
webpack 配置文件(在 webpack 2 中)允许你导出一个 Promise 链,只要最后一步返回一个 webpack 配置对象。请参阅 Promise 配置文档。从那里:
webpack 现在支持从配置文件返回一个 Promise。这允许在您的配置文件中进行异步处理。
您可以创建一个简单的递归复制函数来复制您的文件,并且只有在此之后才会触发 webpack。例如:
module.exports = function(){
return copyTheFiles( inpath, outpath).then( result => {
return { entry: "..." } // Etc etc
} )
}
假设您的所有静态资产都在根级别的“静态”文件夹中,并且您希望将它们复制到维护子文件夹结构的构建文件夹中,然后在您的条目文件中)只需放入
//index.js or index.jsx
require.context("!!file?name=[path][name].[ext]&context=./static!../static/", true, /^\.\/.*\.*/);