如何使用Webpack将静态文件复制到构建目录?

Vit*_*kov 302 javascript webpack

我试图从移动GulpWebpack.在Gulp我有任务将所有文件和文件夹从/ static /文件夹复制到/ build /文件夹.怎么做同样的Webpack?我需要一些插件吗?

kev*_*ned 526

使用文件加载器模块需要资产是webpack的使用方式().但是,如果您需要更大的灵活性或想要更清晰的界面,您也可以使用我的copy-webpack-plugin(npm,Github)直接复制静态文件.为了您staticbuild例如:

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

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

  • 当你想要复制整个目录(即静态html和其他样板图像)时,这简单得多了! (9认同)
  • 诀窍,谢谢你:)在几次失败尝试让它做一个非常简单的命令后放弃了文件加载器.你的插件第一次工作. (5认同)
  • @Yan插件会在文件更改时重新复制文件(dev-server或webpack --watch).如果没有为您复制,请提出问题. (3认同)
  • 我是webpack的新手,但我很难理解为什么我们需要使用file-loader/url-loader/img-loader ...而不是仅仅复制它们?使用文件加载器,我们从中获得的好处是什么? (2认同)
  • 既然你是插件作者.没有更好的速度来问这个问题.使用"copy-webpack-plugin"插件...我可以从源目录中过滤文件,以便它只复制具有特定文件扩展名的文件.只复制".html"?问候 (2认同)
  • 感谢您实际回答标题中提出的实际问题。 (2认同)

Joh*_*ald 176

你不需要复制周围的东西,webpack的工作方式与gulp不同.Webpack是一个模块捆绑器,您将在文件中引用所有内容.你只需要指定一个加载器.

所以,如果你写:

var myImage = require("./static/myImage.jpg");
Run Code Online (Sandbox Code Playgroud)

Webpack将首先尝试将引用的文件解析为JavaScript(因为这是默认值).当然,这将失败.这就是您需要为该文件类型指定加载器的原因.例如,文件 - 或url-loader接受引用的文件,将其放入webpack的输出文件夹(应该是build你的情况)并返回该文件的散列URL.

var myImage = require("./static/myImage.jpg");
console.log(myImage); // '/build/12as7f9asfasgasg.jpg'
Run Code Online (Sandbox Code Playgroud)

通常通过webpack配置应用加载器:

// webpack.config.js

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

当然,您需要先安装文件加载器才能使其正常工作.

  • 是的,如果你想进入webpack插件的地狱,你可以使用文件加载器,css-loader,样式加载器,url-loader,......然后你可以按照你需要的方式配置它谷歌搜索和不睡觉:)或者您可以使用copy-webpack-plugin完成工作... (110认同)
  • "_当然,你需要首先安装文件加载器才能使其工作."链接到前面提到的"文件加载器"[这里](https://github.com/webpack/file-loader).[这里](http://webpack.github.io/docs/using-loaders.html)是如何安装和使用它的. (35认同)
  • 您仍然遇到HTML文件的问题,并且未加载其中的所有引用. (20认同)
  • 好的,所有图像的大部分都是css和html.所以我应该使用require('img.png')在我的JS文件中要求所有这些图像; 使它与该文件加载器一起工作?那太疯狂了. (10认同)
  • @KamilTomšík所以你的建议是我们应该使用webpack插件来避免webpack插件?(开个玩笑.我明白了你的意思.) (8认同)
  • 问题是不能一直工作,我甚至不确定它是否回答问题取决于你如何看待"静态"文件.每个人总是忘记你的代码没有引用的文件.例如,您异步加载的JSON文件怎么样?导入/要求不会出现这些.或者在未导入特定文件路径的情况下动态使用的任何内容?有一个复制webpack插件,但很高兴看到webpack直接处理的东西. (3认同)
  • 我可以在我的 CSS 中使用这些图像吗?我尝试在 css 中使用 url() 但它不起作用。我应该改变路线吗? (2认同)

小智 55

如果要复制静态文件,可以使用以下方式使用文件加载器:

对于html文件:

在webpack.config.js中:

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

在你的js文件中:

  require.context("./static/", true, /^\.\/.*\.html/);
Run Code Online (Sandbox Code Playgroud)

./static/是相对于你的js文件的位置.

你可以用图像或其他任何东西做同样的事情.上下文是一个强大的探索方法!

  • 我更喜欢这种方法而不是copy-webpack-plugin模块.另外,我能够在我的webpack配置中使用"&context =./ app/static"来使其工作.我只需要require.context行. (3认同)
  • 我正在尝试这个,看起来很棒,但是对于我遇到的一个小问题,就是它将我的`index.html`放入一个名为`_`(下划线)的子目录中,发生了什么? (2认同)
  • 当你说“在你的 js 文件中”是什么意思?如果我没有 JS 文件怎么办? (2认同)
  • 这是一个整洁的黑客,但如果你复制太多文件,你将耗尽内存. (2认同)

Dav*_*ald 21

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"
            }
        ]
    }
};
Run Code Online (Sandbox Code Playgroud)

要控制文件的输出方式,您可以使用模板化路径

在配置中,您可以在此处设置全局模板:

// webpack.config.js
module.exports = {
    ...
    output: {
        ...
        assetModuleFilename: '[path][name].[hash][ext][query]'
    }
}
Run Code Online (Sandbox Code Playgroud)

要覆盖一组特定的资产,您可以执行以下操作:

// 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]'
                }
            }
        ]
    }
};
Run Code Online (Sandbox Code Playgroud)

提供的模板将生成类似于build/images/img.151cfcfa1bd74779aadb.png. 哈希对于缓存清除等很有用。您应该根据您的需要进行修改。

  • 另外,尽管您的建议与 doco 完全一致,但没有为我复制任何资产:-\ (3认同)
  • 但出于利益考虑,是否可以从 Tree Shaking 中排除某些规则?对于资产模块来说这样做是有意义的,对吧? (2认同)

ste*_*eev 15

前面提到的copy-webpack-plugin带来的一个优点是之前没有解释过的,这里提到的所有其他方法仍然将资源捆绑到你的bundle文件中(并要求你在某处"要求"或"导入"它们).如果我只想移动一些图像或一些模板部分,我不想混淆我的javascript包文件与无用的引用,我只是想在正确的位置发出的文件.我还没有在webpack中找到任何其他方法.不可否认,这不是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');
}
Run Code Online (Sandbox Code Playgroud)

checkmark.js

var chalk = require('chalk');

/**
 * Adds mark check symbol
 */
function addCheckMark(callback) {
  process.stdout.write(chalk.green(' ?'));
  callback();
}

module.exports = addCheckMark;
Run Code Online (Sandbox Code Playgroud)

添加脚本package.json.假设脚本在<project-root>/scripts/

...
"scripts": {
  "copy": "node scripts/copy.js",
...
Run Code Online (Sandbox Code Playgroud)

运行sript:

npm run copy

  • OP想要完成在webpack中移动的文件,而不是使用npm脚本? (3认同)

And*_*rit 5

最可能的是,您应该使用kevlened答案中提到的CopyWebpackPlugin。另外,对于.html.json之类的文件,您也可以使用raw-loader或json-loader。通过安装它npm install -D raw-loader,然后您只需要在我们的webpack.config.js文件中添加另一个加载器即可。

喜欢:

{
    test: /\.html/,
    loader: 'raw'
}
Run Code Online (Sandbox Code Playgroud)

注意:重新启动webpack-dev-server,使所有配置更改生效。

现在,您可以要求使用相对路径的html文件,这使移动文件夹变得更加容易。

template: require('./nav.html')  
Run Code Online (Sandbox Code Playgroud)


Vic*_*box 5

您可以在 package.json 中编写 bash:

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

  • 对,所以您的解决方案是为每个操作系统使用不同的脚本? (8认同)

Reg*_*Boy 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/'
          },
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

不要忘记安装file-loader以使其正常工作。