10

I have placed a csv file in my assets folder for my react app, however, that file is not getting picked up and added to my dist build via webpack (the images are still added as assets to the build but the csv file is not). You can see my webpack build below. So how do I add a csv file to my dist build via webpack (the goal is for users of my app to be able to download this file)? Thanks!

webpack.dev.js

const merge = require('webpack-merge');
const common = require('./webpack.common.js');

const config = merge(common, {
  mode: 'development',
  devtool: 'inline-source-map',
  devServer: {
    contentBase: './dist',
    historyApiFallback: true,
    hot: true,
    proxy: {
      '/api': {
        target: 'http://localhost:5001',
        secure: false,
      },
    },
    allowedHosts: [
      'localhost',
      'fatpandadev'
    ],
    public: 'fatpandadev:8080'
  },
});

module.exports = config;

webpack.common.js

const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const DIST_DIR = path.resolve(__dirname, "dist");
const SRC_DIR = path.resolve(__dirname, "src");

const config = {
  entry: [
    "babel-polyfill",
    `${SRC_DIR}/app/index.js`,
    `${SRC_DIR}/app/assets/stylesheets/application.scss`,
    `${SRC_DIR}/app/components/index.scss`,
    "font-awesome/scss/font-awesome.scss",
    "react-datepicker/dist/react-datepicker.css",
    "rc-time-picker/assets/index.css",
    "react-circular-progressbar/dist/styles.css",
    "@trendmicro/react-toggle-switch/dist/react-toggle-switch.css",
  ],
  output: {
    path: `${DIST_DIR}/app/`,
    filename: "bundle.js",
    publicPath: "/app/"
  },
  module: {
    rules: [
      {
        enforce: "pre",
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "eslint-loader",
        options: {
          failOnWarning: false,
          failOnError: true
        }
      },
      {
        test: /\.js$/,
        include: SRC_DIR,
        loader: 'babel-loader',
        query: {
          presets: ['react', 'stage-2']
        }
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      },
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader'
        ]
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        loaders: ['file-loader?context=src/images&name=images/[path][name].[ext]', {
          loader: 'image-webpack-loader',
          query: {
            mozjpeg: {
              progressive: true,
            },
            gifsicle: {
              interlaced: false,
            },
            optipng: {
              optimizationLevel: 7,
            },
            pngquant: {
              quality: '75-90',
              speed: 3,
            },
          },
        }],
        exclude: path.resolve(__dirname, "node_modules"),
        include: __dirname,
      },
      {
        test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        // loader: "url?limit=10000"
        use: "url-loader"
      },
      {
        test: /\.(ttf|eot|svg)(\?[\s\S]+)?$/,
        use: 'file-loader'
      },
      {
        test: /\.(txt|csv)$/,
        use: [
          {
            loader: 'file-loader',
            options: {}
          }
        ]
      },
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "application.css"
    })
  ]
};

module.exports = config;
Jimmy
  • 3,090
  • 12
  • 42
  • 99

4 Answers4

8

(this answer is only referenced on the server side)

In addition to @PlayMa256, On Server side(Nodejs runtime), you may need emitFile: true

{
  test: /\.(txt|csv|mmdb)$/,
  use: [
    {
      loader: 'file-loader',
      options: {
        name: "[path][name].[ext]",
        emitFile: true,
      },
    },
  ],
},

Refer to this PR: https://github.com/webpack-contrib/file-loader/pull/135

In my opinion, file-loader way seem to better than copy-webpack-plugin way.

You can test like below:

import csvPath from './assets/data.csv'
console.log(csvPath)          // assets/data.csv

Tested version:

$ cat node_modules/webpack/package.json | jq .version
"4.29.5"
$ cat node_modules/file-loader/package.json | jq .version
"3.0.1"
Alfred
  • 1,276
  • 11
  • 19
  • 3
    Worked perfectly. – Viraths May 01 '19 at 23:53
  • OP stated *the goal is for users of my app to be able to download this file*. While your answer is certainly useful for people in need of importing a file in a string to process in Javascript, it does not help with OP's stated needs. – connexo Dec 11 '20 at 19:47
  • @connexo That's a good point. This method emits a file with the same path as the path obtained by import on the server side. If you know the actual path of the file, it is not difficult to provide it by download. – Alfred Dec 14 '20 at 04:06
  • Strangely getting a module not found error here on the import, while the file is being served at localhost:8080/assets/data.csv – Dr. Andrew Burnett-Thompson Jan 23 '22 at 10:37
3

You might want to check the CopyWebpackPlugin if you have no need to process/parse the files, but only to copy them to your dist folder.

Copy Webpack Plugin

Copies individual files or entire directories to the build directory

Install

npm i -D copy-webpack-plugin

Usage

webpack.config.js

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

const config = {
    plugins: [
      new CopyWebpackPlugin([ ...patterns ], options)
    ]
  }

Patterns

A simple pattern looks like this

{ from: 'source', to: 'dest' }
connexo
  • 53,704
  • 14
  • 91
  • 128
  • 2
    but what if i don't want a tool to turn my csv files into json, but instead have my csv files be downloadable by my users (and thus be an externally facing asset)? – Jimmy Sep 06 '18 at 19:08
  • upvoted. I tried many permutations of using the `file-loader` (in both webpack 4 and 5.10); nothing worked and I couldn't "load" a CSV file, even though, curiously, I was able to "load" JSON files. In the end I used CopyWebpackPlugin and the pain was over – Marcus Junius Brutus Dec 11 '20 at 16:26
2
{
        test: /\.(txt|csv)$/,
        use: [
          {
            loader: 'file-loader',
            options: {}
          }
        ]
      }

You should import you csv file as you import your images too.

PlayMa256
  • 6,603
  • 2
  • 34
  • 54
2

import your csv files using raw-loader,

{
          test: /\.csv$/i,
          use:  'raw-loader',
}
Reza
  • 31
  • 5