如何使用 Webpack 复制静态文件以构建目录

How to copy static files to build directory with Webpack?

本文关键字:构建 文件 静态 何使用 Webpack 复制      更新时间:2023-09-26

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

要求使用文件加载器模块的资产是 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({
            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 加载器获取引用的文件,将其放入 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 .哈希对于缓存破坏等很有用。您应该根据需要进行修改。

以上建议很好。 但是要尝试直接回答您的问题,我建议在您的package.json中定义的脚本中使用cpy-cli

此示例期望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",
...

要运行 sript,请执行以下操作:

npm run copy

我加载静态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才能使其正常工作。

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

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

很可能你应该使用凯夫伦德答案中提到的CopyWebpackPlugin。或者,对于某些类型的文件,如.html或.json,您也可以使用原始加载器或json加载器。通过npm install -D raw-loader安装它,然后您只需要将另一个加载程序添加到我们的webpack.config.js文件中。

喜欢:

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

注意:重新启动 webpack-dev-server 以使任何配置更改生效。

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

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

我也被困在这里。 复制-webpack-插件为我工作。

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

webpack 忽略根路径

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

因此,要在不使用"复制-webpack-plugin"的情况下完成这项工作在路径中使用"~"

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

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

注意:您可能需要在

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

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

webpack 配置文件(在 webpack 2 中)允许你导出一个承诺链,只要最后一步返回一个 webpack 配置对象。请参阅承诺配置文档。从那里:

webpack 现在支持从配置文件返回一个承诺。这允许在配置文件中进行异步处理。

您可以创建一个简单的递归复制函数来复制您的文件,并且只有在该函数之后才会触发 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, /^'.'/.*'.*/);

就我而言,我使用 webpack 作为 wordpress 插件来压缩 js 文件,其中插件文件已经压缩并且需要跳过该过程。

optimization: {
    minimize: false,
},
externals: {
    "jquery": "jQuery",
},
entry: glob.sync('./js/plugin/**.js').reduce(function (obj, el) {
    obj[path.parse(el).name] = el;
    return obj
}, {}),
output: {
    path: path.resolve(__dirname, './js/dist/plugin'),
    filename: "[name].js",
    clean: true,
},

这曾经用于将 js 文件原样复制到构建文件夹。使用任何其他方法,如文件加载器和复制webpack,都会产生问题。

希望它能帮助某人。