简体   繁体   English

如何将 static 文件复制到带有 Webpack 的构建目录?

[英]How to copy static files to build directory with Webpack?

I'm trying to move from Gulp to Webpack .我正在尝试从Gulp移动到Webpack In Gulp I have task which copies all files and folders from /static/ folder to /build/ folder.Gulp ,我有将所有文件和文件夹从/static/文件夹复制到/build/文件夹的任务。 How to do the same with Webpack ?如何对Webpack做同样的事情? Do I need some plugin?我需要一些插件吗?

Requiring assets using the file-loader module is the way webpack is intended to be used ( source ).使用 file-loader 模块请求资产是 webpack 的预期使用方式( source )。 However, if you need greater flexibility or want a cleaner interface, you can also copy static files directly using my copy-webpack-plugin ( npm , Github ).但是,如果您需要更大的灵活性或想要更简洁的界面,您也可以使用我的copy-webpack-plugin ( npm , Github ) 直接复制静态文件。 For your static to build example:对于您的static build示例:

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

Compatibility note: If you're using an old version of webpack like webpack@4.xx , use copy-webpack-plugin@6.xx .兼容性说明:如果您使用的是旧版本的 webpack,例如webpack@4.xx ,请使用copy-webpack-plugin@6.xx Otherwise use latest.否则使用最新的。

You don't need to copy things around, webpack works different than gulp.你不需要到处复制东西,webpack 的工作方式与 gulp 不同。 Webpack is a module bundler and everything you reference in your files will be included. Webpack 是一个模块捆绑器,您在文件中引用的所有内容都将包含在内。 You just need to specify a loader for that.您只需要为此指定一个加载程序。

So if you write:所以如果你写:

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

Webpack will first try to parse the referenced file as JavaScript (because that's the default). Webpack 将首先尝试将引用的文件解析为 JavaScript(因为这是默认设置)。 Of course, that will fail.当然,那会失败。 That's why you need to specify a loader for that file type.这就是您需要为该文件类型指定加载程序的原因。 The file - or url-loader for instance take the referenced file, put it into webpack's output folder (which should be build in your case) and return the hashed url for that file.文件- 或url-loader例如获取引用的文件,将其放入 webpack 的输出文件夹(应在您的情况下build )并返回该文件的散列 url。

var myImage = require("./static/myImage.jpg");
console.log(myImage); // '/build/12as7f9asfasgasg.jpg'

Usually loaders are applied via the webpack config:通常加载器是通过 webpack 配置应用的:

// webpack.config.js

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

Of course you need to install the file-loader first to make this work.当然,您需要先安装文件加载器才能完成这项工作。

If you want to copy your static files you can use the file-loader in this way :如果要复制静态文件,可以通过以下方式使用文件加载器:

for html files :对于 html 文件:

in webpack.config.js :在 webpack.config.js 中:

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

in your js file :在你的 js 文件中:

  require.context("./static/", true, /^\.\/.*\.html/);

./static/ is relative to where your js file is. ./static/ 相对于您的 js 文件所在的位置。

You can do the same with images or whatever.你可以对图像或其他东西做同样的事情。 The context is a powerful method to explore !!上下文是一种强大的探索方法!

One advantage that the aforementioned copy-webpack-plugin brings that hasn't been explained before is that all the other methods mentioned here still bundle the resources into your bundle files (and require you to "require" or "import" them somewhere).前面提到的copy-webpack-plugin带来的一个之前没有解释过的优点是,这里提到的所有其他方法仍然将资源捆绑到你的包文件中(并且要求你在某处“要求”或“导入”它们)。 If I just want to move some images around or some template partials, I don't want to clutter up my javascript bundle file with useless references to them, I just want the files emitted in the right place.如果我只想移动一些图像或一些模板部分,我不想用对它们的无用引用来弄乱我的 javascript 包文件,我只希望在正确的位置发出文件。 I haven't found any other way to do this in webpack.我还没有在 webpack 中找到任何其他方法来做到这一点。 Admittedly it's not what webpack originally was designed for, but it's definitely a current use case.诚然,这不是 webpack 最初设计的目的,但它绝对是当前的用例。 (@BreakDS I hope this answers your question - it's only a benefit if you want it) (@BreakDS 我希望这能回答你的问题——如果你想要的话,这只是一个好处)

Webpack 5 adds Asset Modules which are essentially replacements for common file loaders. Webpack 5 添加了资产模块,这些模块本质上是普通文件加载器的替代品。 I've copied a relevant portion of the documentation below:我复制了以下文档的相关部分:

  • asset/resource emits a separate file and exports the URL. asset/resource发出一个单独的文件并导出 URL。 Previously achievable by using file-loader .以前可以通过使用file-loader来实现。
  • asset/inline exports a data URI of the asset. asset/inline导出资产的数据 URI。 Previously achievable by using url-loader .以前可以通过使用url-loader来实现。
  • asset/source exports the source code of the asset. asset/source导出资产的源代码。 Previously achievable by using raw-loader .以前可以通过使用raw-loader来实现。
  • asset automatically chooses between exporting a data URI and emitting a separate file. asset自动在导出数据 URI 和发出单独文件之间进行选择。 Previously achievable by using url-loader with asset size limit.以前可以通过使用带有资产大小限制的url-loader来实现。

To add one in you can make your config look like so:要添加一个,您可以使您的配置看起来像这样:

// webpack.config.js

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

To control how the files get output, you can use templated paths .要控制文件如何获得输出,您可以使用 模板路径

In the config you can set the global template here:在配置中,您可以在此处设置全局模板:

// webpack.config.js
module.exports = {
    ...
    output: {
        ...
        assetModuleFilename: '[path][name].[hash][ext][query]'
    }
}

To override for a specific set of assets, you can do this:要覆盖一组特定的资产,您可以执行以下操作:

// 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]'
                }
            }
        ]
    }
};

The provided templating will result in filenames that look like build/images/img.151cfcfa1bd74779aadb.png .提供的模板将生成类似于build/images/img.151cfcfa1bd74779aadb.png的文件名。 The hash can be useful for cache busting etc. You should modify to your needs.哈希对于缓存破坏等很有用。您应该根据需要进行修改。

Above suggestions are good.以上建议都不错。 But to try to answer your question directly I'd suggest using cpy-cli in a script defined in your package.json .但要尝试直接回答您的问题,我建议在您的package.json定义的脚本中使用cpy-cli

This example expects node to somewhere on your path.此示例期望node位于您路径上的某个位置。 Install cpy-cli as a development dependency:安装cpy-cli作为开发依赖项:

npm install --save-dev cpy-cli

Then create a couple of nodejs files.然后创建几个 nodejs 文件。 One to do the copy and the other to display a checkmark and message.一个用于复制,另一个用于显示复选标记和消息。

copy.js复制.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复选标记.js

var chalk = require('chalk');

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

module.exports = addCheckMark;

Add the script in package.json .package.json中添加脚本。 Assuming scripts are in <project-root>/scripts/假设脚本在<project-root>/scripts/

...
"scripts": {
  "copy": "node scripts/copy.js",
...

To run the sript:要运行脚本:

npm run copy

The way I load static images and fonts :我加载静态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/'
          },
        }
    ]
}

Don't forget to install file-loader to have that working.不要忘记安装file-loader以使其正常工作。

You can write bash in your package.json:您可以在 package.json 中编写 bash:

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

Most likely you should use CopyWebpackPlugin which was mentioned in kevlened answer.您很可能应该使用 kevlened 答案中提到的 CopyWebpackPlugin。 Alternativly for some kind of files like .html or .json you can also use raw-loader or json-loader.对于某些类型的文件,例如.html.json ,您也可以使用 raw-loader 或 json-loader。 Install it via npm install -D raw-loader and then what you only need to do is to add another loader to our webpack.config.js file.通过npm install -D raw-loader安装它,然后您只需在我们的webpack.config.js文件中添加另一个加载器。

Like:喜欢:

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

Note: Restart the webpack-dev-server for any config changes to take effect.注意:重新启动 webpack-dev-server 以使任何配置更改生效。

And now you can require html files using relative paths, this makes it much easier to move folders around.现在您可以使用相对路径来请求 html 文件,这使得移动文件夹变得更加容易。

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

I was stuck here too.我也被困在这里。 copy-webpack-plugin worked for me. copy-webpack-plugin 为我工作。

However, 'copy-webpack-plugin' was not necessary in my case (i learned later).但是,在我的情况下,“copy-webpack-plugin”不是必需的(我后来才知道)。

webpack ignores root paths webpack 忽略根路径
example例子

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

Hence, to make this work without using 'copy-webpack-plugin' use '~' in paths因此,要在不使用 'copy-webpack-plugin' 的情况下完成这项工作,请在路径中使用 '~'

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

'~' tells webpack to consider 'images' as a module '~' 告诉 webpack 将 'images' 视为一个模块

note: you might have to add the parent directory of images directory in注意:您可能必须添加图像目录的父目录

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

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

The webpack config file (in webpack 2) allows you to export a promise chain, so long as the last step returns a webpack config object. webpack 配置文件(在 webpack 2 中)允许你导出一个 Promise 链,只要最后一步返回一个 webpack 配置对象。 See promise configuration docs . 请参阅 Promise 配置文档 From there:从那里:

webpack now supports returning a Promise from the configuration file. webpack 现在支持从配置文件返回一个 Promise。 This allows to do async processing in you configuration file.这允许在您的配置文件中进行异步处理。

You could create a simple recursive copy function that copies your file, and only after that triggers webpack.您可以创建一个简单的递归复制函数来复制您的文件,并且只有在此之后才会触发 webpack。 Eg:例如:

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

lets say all your static assets are in a folder "static" at the root level and you want copy them to the build folder maintaining the structure of subfolder, then in your entry file) just put假设您的所有静态资产都在根级别的“静态”文件夹中,并且您希望将它们复制到维护子文件夹结构的构建文件夹中,然后在您的条目文件中)只需放入

//index.js or index.jsx

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

if copyrights to files are correct文件的版权是否正确

here is ultimate solution for this thread with pictures and command explanations.这是该线程的最终解决方案,带有图片和命令说明。

sometimes folders are overwritten during copy, that is why folder error appears有时文件夹在复制过程中被覆盖,这就是出现文件夹错误的原因

https://stackoverflow.com/a/72959857/4452831 https://stackoverflow.com/a/72959857/4452831

In my case I used webpack for a wordpress plugin to compress js files, where the plugin files are already compressed and need to skip from the process.在我的情况下,我使用 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,
},

That used to copy the js file as it is to the build folder.用于将 js 文件原样复制到构建文件夹。 Using any other methods like file-loader and copy-webpack create issues with that.使用任何其他方法,如 file-loader 和 copy-webpack 都会产生问题。

Hope it will help someone.希望它会帮助某人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM