webpack-contrib / file-loader

File Loader
MIT License
1.86k stars 255 forks source link

Font Face URL Doesn't Target dist Folder #363

Closed RezaZR closed 4 years ago

RezaZR commented 4 years ago

Hi, please help me anyone.

I add font-face on my _main.scss and then i build and send it to dist folder. Here is my project's structure:

image

Expected Behavior

I want the url inside main.[hash].css under dist folder targeting to dist, not targeting to src.

Actual Behavior

The url inside main.[hash].css target src. Here is the piece of code inside main.[hash].css:

image

Code

// webpack.common.js
const VueLoaderPlugin = require("vue-loader/lib/plugin");

const path = require("path");

module.exports = {
  entry: {
    main: "./src/main.js",
    vendor: "./src/vendor.js"
  },
  plugins: [new VueLoaderPlugin()],
  module: {
    rules: [
      { test: /\.js$/, use: "babel-loader" },
      { test: /\.vue$/, use: "vue-loader" },
      {
        test: /\.(svg|jpg|jpeg|png|gif)(\?.*$|$)/,
        use: {
          loader: "file-loader",
          options: {
            name: "[name].[hash].[ext]",
            outputPath: "images",
            esModule: false
          }
        }
      },
      {
        test: /\.(woff(2)?|ttf|eot)$/,
        use: {
          loader: "file-loader",
          options: {
            name: "[name].[hash].[ext]",
            outputPath: "fonts",
            esModule: true
          }
        }
      }
    ]
  }
};
// webpack.prod.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");

const { CleanWebpackPlugin } = require("clean-webpack-plugin");

const path = require("path");
const common = require("./webpack.common");
const merge = require("webpack-merge");

module.exports = merge(common, {
  mode: "production",
  output: {
    filename: "[name].[hash].js",
    path: path.resolve(__dirname, "dist")
  },
  optimization: {
    minimizer: [
      new HtmlWebpackPlugin({
        template: "./src/index.html",
        minify: {
          removeAttributeQuotes: true,
          collapseWhitespace: true,
          removeComments: true
        }
      }),
      new OptimizeCssAssetsPlugin(),
      new TerserPlugin()
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({ filename: "[name].[hash].css" }),
    new CleanWebpackPlugin()
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: { sourceMap: true }
          }
        ]
      },
      {
        test: /\.s[ac]ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: { sourceMap: true }
          },
          {
            loader: "sass-loader",
            options: {
              prependData: `
                @import "./src/assets/styles/_main.scss";
              `
            }
          }
        ]
      }
    ]
  }
});
// package.json
{
  "scripts": {
    "serve": "webpack-dev-server --config webpack.dev.js --open",
    "build": "webpack --config webpack.prod.js"
  },
  "devDependencies": {
    "@babel/core": "^7.8.3",
    "@babel/preset-env": "^7.8.3",
    "babel-loader": "^8.0.6",
    "bootstrap": "^4.4.1",
    "css-loader": "^3.4.2",
    "file-loader": "^5.0.2",
    "html-webpack-plugin": "^3.2.0",
    "jquery": "^3.4.1",
    "mini-css-extract-plugin": "^0.9.0",
    "node-sass": "^4.13.1",
    "optimize-css-assets-webpack-plugin": "^5.0.3",
    "popper.js": "^1.16.1",
    "sass-loader": "^8.0.2",
    "url-loader": "^3.0.0",
    "vue": "^2.6.11",
    "vue-loader": "^15.8.3",
    "vue-style-loader": "^4.1.2",
    "vue-template-compiler": "^2.6.11",
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.10.1",
    "webpack-merge": "^4.2.2"
  },
  "dependencies": {
    "clean-webpack-plugin": "^3.0.0"
  }
}
// _main.scss
@import "~bootstrap/scss/bootstrap";

@font-face {
  font-family: Rubik;
  src: url("/src/assets/fonts/Rubik-Regular.ttf") format("truetype");
}

body {
  background: antiquewhite;
  font-family: Rubik;
}

Please help me

anikethsaha commented 4 years ago

you should give relative paths with proper project structure so that the environment in src can be replicated in dist as well. You need to make changes to your project structure. In general, assets are something that you don't want to keep inside the src folder. it can be in the root so when deploying your site, it will be deployed as a separate folder in root as well so you can link the images without any issues. the second thing you can do is try to replicate the src folder in the dist folder so you won't face these issues. copy the assets folder as well to dist use copy-plugin for these things.

I would prefer the second option of moving the assets folder to dist as well for your case as you are processing files in there as well.

RezaZR commented 4 years ago

@anikethsaha hello, thank you for your answer but can you give me example how to replicate src to dist using webpack?

anikethsaha commented 4 years ago

use https://github.com/webpack-contrib/file-loader#publicpath and https://github.com/webpack-contrib/file-loader#outputpath and for files which are not processed through any loader rules, use copy plugin for that

alexander-akait commented 4 years ago

Answer above, feel free to leave feedback