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

时间:2014-12-24 15:20:53

标签: javascript webpack

我正试图从Gulp转到Webpack。在Gulp我有将 / static / 文件夹中的所有文件和文件夹复制到 / build / 文件夹的任务。如何对Webpack做同样的事情?我需要一些插件吗?

12 个答案:

答案 0 :(得分:467)

使用文件加载器模块查询资源是webpack的使用方式(source)。但是,如果您需要更大的灵活性或想要更清晰的界面,您还可以使用我的copy-webpack-pluginnpmGithub)直接复制静态文件。对于您的staticbuild示例:

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

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

答案 1 :(得分:173)

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

所以如果你写:

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

Webpack将首先尝试将引用的文件解析为JavaScript(因为这是默认值)。当然,这将失败。这就是您需要为该文件类型指定加载器的原因。例如file - 或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" }
        ]
    }
};

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

答案 2 :(得分:53)

如果要复制静态文件,可以这样使用文件加载器:

用于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 :(得分:8)

前面提到的 copy-webpack-plugin 带来的一个优点是,此处提到的所有其他方法仍然将资源捆绑到您的捆绑文件中(并要求您to"要求"或"导入"他们某处)。如果我只想移动一些图像或一些模板部分,我不想混淆我的javascript包文件与无用的引用,我只是想在正确的位置发出的文件。我还没有找到任何其他方法在webpack中这样做。不可否认,这不是webpack最初的设计目标,但它绝对是当前的用例。 (@BreakDS我希望这能回答你的问题 - 如果你想要的话,这只是一个好处)

答案 4 :(得分: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",
...

运行sript:

npm run copy

答案 5 :(得分:4)

最有可能你应该使用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')  

答案 6 :(得分:3)

我加载静态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/'
          },
        }
    ]
}

请不要忘记安装file-loader才能使它正常工作。

答案 7 :(得分:2)

我也被困在这里。 copy-webpack-plugin为我工作。

但是,在我的情况下,我不需要'copy-webpack-plugin'(我后来才知道)。

webpack忽略根路径
示例

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

因此,要在不使用'copy-webpack-plugin'的情况下完成这项工作 在路径中使用'〜'

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

'〜'告诉webpack将'images'视为一个模块

请注意: 您可能必须在

中添加images目录的父目录
resolve: {
    modules: [
        'parent-directory of images',
        'node_modules'
    ]
}

访问https://vuejs-templates.github.io/webpack/static.html

答案 8 :(得分:2)

webpack配置文件(在webpack 2中)允许您导出promise链,只要最后一步返回webpack配置对象。 See promise configuration docs。从那里:

  

webpack现在支持从配置文件中返回Promise。这允许在配置文件中执行异步处理。

您可以创建一个简单的递归复制函数来复制您的文件,并且只有在触发了webpack之后才能复制。 E.g:

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

答案 9 :(得分:1)

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

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

答案 10 :(得分:1)

假设所有静态资源都位于根级别的“静态”文件夹中,并且您希望将它们复制到维护子文件夹结构的构建文件夹,然后 在您的输入文件中)只需输入

//index.js or index.jsx

require.context("!!file?name=[path][name].[ext]&context=./static!../static/", true, /^\.\/.*\.*/);

答案 11 :(得分:1)

Webpack 5 添加了 Asset Modules,它本质上是对常见文件加载器的替代。我复制了以下文档的相关部分:

  • 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"
            }
        ]
    }
};

您可以使用 templated paths 处理如何复制文件。对于所有资产的默认模板,您可以执行以下操作:

// 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。根据您的用例修改模板。