brandonkramer / wordpress-webpack-workflow

Common tools to facilitate front-end development and testing for WordPress (plugins & themes). Includes WebPack 5, BrowserSync, PostCSS/Autoprefixer, PurgeCSS, BabelJS, Eslint, Stylelint, SCSS processor, WP-Pot, an organized file structure and more.
103 stars 22 forks source link

Issue loading @font-face #4

Open dayneh88 opened 3 years ago

dayneh88 commented 3 years ago

Hi,

Having issues trying to get @font-face to work when it's declared in a SASS file. The fonts sit in: assets/src/fonts and the SASS file sits in: assets/src/sass/abstracts/_fonts.scss

I'm declaring my @font-face like this:

@font-face {
  font-family: 'Noigrotesk-Ultra-Light';
  src: url('/assets/src/fonts/noigrotesk-100-normal.woff2') format('woff2'), url('/assets/src/fonts/noigrotesk-100-normal.woff') format('woff');
  font-weight: 100;
}

My console is erroring:

ERROR in ./assets/src/sass/app.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleParseError: Module parse failed: Unexpected character '' (1:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

I've seen things like url-loader but I can't find where in the webpack.config.js file where to put it.

Any help would be greatly appreciated!

esalexreyes commented 3 years ago

Hi,

Having issues trying to get @font-face to work when it's declared in a SASS file. The fonts sit in: assets/src/fonts and the SASS file sits in: assets/src/sass/abstracts/_fonts.scss

I'm declaring my @font-face like this:

@font-face {
  font-family: 'Noigrotesk-Ultra-Light';
  src: url('/assets/src/fonts/noigrotesk-100-normal.woff2') format('woff2'), url('/assets/src/fonts/noigrotesk-100-normal.woff') format('woff');
  font-weight: 100;
}

My console is erroring:

ERROR in ./assets/src/sass/app.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleParseError: Module parse failed: Unexpected character '' (1:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

I've seen things like url-loader but I can't find where in the webpack.config.js file where to put it.

Any help would be greatly appreciated!

@dayneh88 As I said in another thread, I no longer use this configuration, but I tried to adapt the fonts, so they actually work. I hope this works as the basis for what you are working on. This only changes all the webpack config files, nothing else. :)

/**
 * This is the main entry point for Webpack config.
 *
 * @since 1.0.0
 */
const path = require('path');

// Paths to find our files and provide BrowserSync functionality.
const projectPaths = {
  projectDir: __dirname, // Current project directory absolute path.
  projectJsPath: path.resolve(__dirname, 'assets/src/js'),
  projectScssPath: path.resolve(__dirname, 'assets/src/scss'),
  projectImagesPath: path.resolve(__dirname, 'assets/src/img'),
  projectFontsPath: path.resolve(__dirname, 'assets/src/fonts'),
  projectOutput: path.resolve(__dirname, 'assets/public'),
  projectWebpack: path.resolve(__dirname, 'webpack'),
};

// Files to bundle
const projectFiles = {
  // BrowserSync settings
  browserSync: {
    enable: true, // enable or disable browserSync
    host: 'localhost',
    port: 3600,
    mode: 'proxy', // proxy | server
    server: { baseDir: ['public'] }, // can be ignored if using proxy
    proxy: 'https://rathalos.test/', // ! Change this to your test domain
    // BrowserSync will automatically watch for changes to any files connected to our entry,
    // including both JS and Sass files. We can use this property to tell BrowserSync to watch
    // for other types of files, in this case PHP files, in our project.
    files: '**/**/**.php',
    reload: true, // Set false to prevent BrowserSync from reloading and let Webpack Dev Server take care of this
    // browse to http://localhost:3000/ during development,
    https: {
      key: '/home/alex/devilbox/ca/certs/main/localhost.key', // ! Add your own key and cert, be sure to expose them if using devilbox
      cert: '/home/alex/devilbox/ca/certs/main/localhost.crt',
    },
  },

  // JS configurations for development and production
  projectJs: {
    eslint: true, // enable or disable eslint  | this is only enabled in development env.
    filename: 'js/[name].js',
    entry: {
      frontend: `${projectPaths.projectJsPath}/frontend.js`,
      backend: `${projectPaths.projectJsPath}/backend.js`,
    },
    rules: {
      test: /\.m?js$/,
    },
  },

  // CSS configurations for development and production
  projectCss: {
    postCss: `${projectPaths.projectWebpack}/postcss.config.js`,
    stylelint: true, // enable or disable stylelint | this is only enabled in development env.
    filename: 'css/[name].css',
    use: 'sass', // sass || postcss
    // ^ If you want to change from Sass to PostCSS or PostCSS to Sass then you need to change the
    // styling files which are being imported in "assets/src/js/frontend.js" and "assets/src/js/backend.js".
    // So change "import '../sass/backend.scss'" to "import '../postcss/backend.pcss'" for example
    rules: {
      sass: {
        test: /\.s[ac]ss$/i,
      },
      postcss: {
        test: /\.pcss$/i,
      },
    },
    purgeCss: {
      // PurgeCSS is only being activated in production environment
      paths: [
        // Specify content that should be analyzed by PurgeCSS
        `${__dirname}/assets/src/js/**/*`,
        `${__dirname}/templates/**/**/*`,
        `${__dirname}/template-parts/**/**/*`,
        `${__dirname}/blocks/**/**/*`,
        `${__dirname}/*.php`,
      ],
    },
  },

  // Source Maps configurations
  projectSourceMaps: {
    // Sourcemaps are nice for debugging but takes lots of time to compile,
    // so we disable this by default and can be enabled when necessary
    enable: false,
    env: 'dev', // dev | dev-prod | prod
    // ^ Enabled only for development on default, use "prod" to enable only for production
    // or "dev-prod" to enable it for both production and development
    devtool: 'source-map', // type of sourcemap, see more info here: https://webpack.js.org/configuration/devtool/
    // ^ If "source-map" is too slow, then use "cheap-source-map" which struck a good balance between build performance and debuggability.
  },

  // Images configurations for development and production
  projectImages: {
    rules: {
      test: /\.(jpe?g|png|gif|svg)$/i,
    },
    // Optimization settings
    minimizerOptions: {
      // Lossless optimization with custom option
      // Feel free to experiment with options for better result for you
      // More info here: https://webpack.js.org/plugins/image-minimizer-webpack-plugin/
      plugins: [
        ['gifsicle', { interlaced: true }],
        ['jpegtran', { progressive: true }],
        ['optipng', { optimizationLevel: 5 }],
        [
          'svgo',
          {
            plugins: [{ removeViewBox: false }],
          },
        ],
      ],
    },
  },
};

// Merging the projectFiles & projectPaths objects
const projectOptions = {
  ...projectPaths,
  ...projectFiles,
  projectConfig: {
    // add extra options here
  },
};

// Get the development or production setup based
// on the script from package.json
module.exports = (env) => {
  if (env.NODE_ENV === 'production') {
    return require('./webpack/config.production')(projectOptions);
  }
  return require('./webpack/config.development')(projectOptions);
};
/**
 * This holds the configuration that is being used for both development and production.
 * This is being imported and extended in the config.development.js and config.production.js files
 *
 * @since 1.1.0
 */

const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // Extracts the CSS files into public/css
const BrowserSyncPlugin = require('browser-sync-webpack-plugin'); // Synchronising URLs, interactions and code changes across devices
const WebpackBar = require('webpackbar'); // Display elegant progress bar while building or watch
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin'); // To optimize (compress) all images using
const CopyPlugin = require('copy-webpack-plugin'); // For WordPress we need to copy images from src to public to optimize them

module.exports = (projectOptions) => {
  /**
   * CSS Rules
   */
  const cssRules = {
    test:
      projectOptions.projectCss.use === 'sass'
        ? projectOptions.projectCss.rules.sass.test
        : projectOptions.projectCss.rules.postcss.test,
    exclude: /(node_modules|bower_components|vendor)/,
    use: [
      MiniCssExtractPlugin.loader, // Creates `style` nodes from JS strings
      'css-loader', // Translates CSS into CommonJS
      {
        // loads the PostCSS loader
        loader: 'postcss-loader',
        options: require(projectOptions.projectCss.postCss)(projectOptions),
      },
      {
        // Compiles Sass to CSS
        loader: 'sass-loader',
      },
    ],
  };

  /**
   * JavaScript rules
   */
  const jsRules = {
    test: projectOptions.projectJs.rules.test,
    include: projectOptions.projectJsPath,
    exclude: /(node_modules|bower_components|vendor)/,
    use: 'babel-loader', // Configurations in "webpack/babel.config.js"
  };

  /**
   * Images rules
   */
  const imageRules = {
    test: projectOptions.projectImages.rules.test,
    type: 'asset/resource',
    generator: {
      publicPath: '../images/',
      filename: '[name][ext]',
      emit: false,
    },
  };

  /**
   * Font rules
   */
  const fontRules = {
    test: /\.(eot|ttf|woff|woff2)$/i,
    include: projectOptions.projectFontsPath,
    exclude: /(node_modules|bower_components|vendor)/,
    type: 'asset/resource',
    generator: {
      publicPath: '../',
      filename: 'fonts/[name][ext]',
    },
  };

  /**
   * Optimization rules
   */
  const optimizations = {};

  /**
   * Plugins
   */
  const plugins = [
    new WebpackBar(), // Adds loading bar during builds
    // Uncomment this to enable profiler https://github.com/nuxt-contrib/webpackbar#options
    // { reporters: [ 'profile' ], profile: true }
    new MiniCssExtractPlugin({
      // Extracts CSS files
      filename: projectOptions.projectCss.filename,
    }),
    new CopyPlugin({
      // Copies images from src to public
      patterns: [
        {
          from: projectOptions.projectImagesPath,
          to: `${projectOptions.projectOutput}/images`,
        },
      ],
    }),
    new ImageMinimizerPlugin({
      // Optimizes images
      minimizerOptions: projectOptions.projectImages.minimizerOptions,
    }),
  ];

  // Add browserSync to plugins if enabled
  if (projectOptions.browserSync.enable === true) {
    const browserSyncOptions = {
      files: projectOptions.browserSync.files,
      host: projectOptions.browserSync.host,
      port: projectOptions.browserSync.port,
      https: projectOptions.browserSync.https,
    };
    if (projectOptions.browserSync.mode === 'server') {
      Object.assign(browserSyncOptions, {
        server: projectOptions.browserSync.server,
      });
    } else {
      Object.assign(browserSyncOptions, {
        proxy: projectOptions.browserSync.proxy,
      });
    }
    plugins.push(
      new BrowserSyncPlugin(browserSyncOptions, {
        reload: projectOptions.browserSync.reload,
      })
    );
  }

  return {
    cssRules,
    jsRules,
    imageRules,
    fontRules,
    optimizations,
    plugins,
  };
};
/**
 * Webpack configurations for the development environment
 * based on the script from package.json
 * Run with: "npm run dev" or "npm run dev:watch"
 *
 * @since 1.0.0
 */

const ESLintPlugin = require('eslint-webpack-plugin'); //  Find and fix problems in your JavaScript code
const StylelintPlugin = require('stylelint-webpack-plugin'); // Helps you avoid errors and enforce conventions in your styles

module.exports = (projectOptions) => {
  process.env.NODE_ENV = 'development'; // Set environment level to 'development'

  /**
   * The base skeleton
   */
  const Base = require('./config.base')(projectOptions);

  /**
   * CSS rules
   */
  const cssRules = {
    ...Base.cssRules,
    ...{
      // add CSS rules for development here
    },
  };

  /**
   * JS rules
   */
  const jsRules = {
    ...Base.jsRules,
    ...{
      // add JS rules for development here
    },
  };

  /**
   * Image rules
   */
  const imageRules = {
    ...Base.imageRules,
    ...{
      // add image rules for development here
    },
  };

  /**
   * font rules
   */
  const fontRules = {
    ...Base.fontRules,
    ...{
      // add image rules for development here
    },
  };

  /**
   * Optimizations rules
   */
  const optimizations = {
    ...Base.optimizations,
    ...{
      // add optimizations rules for development here
    },
  };

  /**
   * Plugins
   */
  const plugins = [
    ...Base.plugins,
    ...[
      // add plugins for development here
    ],
  ];
  // Add eslint to plugins if enabled
  if (projectOptions.projectJs.eslint === true) {
    plugins.push(new ESLintPlugin());
  }
  // Add stylelint to plugins if enabled
  if (projectOptions.projectJs.eslint === true) {
    plugins.push(new StylelintPlugin());
  }

  /** *
   * Add sourcemap for development if enabled
   */
  const sourceMap = { devtool: false };
  if (
    projectOptions.projectSourceMaps.enable === true &&
    (projectOptions.projectSourceMaps.env === 'dev' ||
      projectOptions.projectSourceMaps.env === 'dev-prod')
  ) {
    sourceMap.devtool = projectOptions.projectSourceMaps.devtool;
  }

  /**
   * The configuration that's being returned to Webpack
   */
  return {
    mode: 'development',
    entry: projectOptions.projectJs.entry, // Define the starting point of the application.
    output: {
      path: projectOptions.projectOutput,
      filename: projectOptions.projectJs.filename,
    },
    devtool: sourceMap.devtool,
    optimization: optimizations,
    module: { rules: [cssRules, jsRules, imageRules, fontRules] },
    plugins,
  };
};
/**
 * Webpack configurations for the production environment
 * based on the script from package.json
 * Run with: "npm run prod" or or "npm run prod:watch"
 *
 * @since 1.0.0
 */
const glob = require('glob-all');
// const PurgecssPlugin = require('purgecss-webpack-plugin'); // A tool to remove unused CSS

module.exports = (projectOptions) => {
  process.env.NODE_ENV = 'production'; // Set environment level to 'production'

  /**
   * The base skeleton
   */
  const Base = require('./config.base')(projectOptions);

  /**
   * CSS rules
   */
  const cssRules = {
    ...Base.cssRules,
    ...{
      // add CSS rules for production here
    },
  };

  /**
   * JS rules
   */
  const jsRules = {
    ...Base.jsRules,
    ...{
      // add JS rules for production here
    },
  };

  /**
   * Image rules
   */
  const imageRules = {
    ...Base.imageRules,
    ...{
      // add image rules for production here
    },
  };

  /**
   * font rules
   */
  const fontRules = {
    ...Base.fontRules,
    ...{
      // add image rules for development here
    },
  };

  /**
   * Optimizations rules
   */
  const optimizations = {
    ...Base.optimizations,
    ...{
      splitChunks: {
        cacheGroups: {
          styles: {
            // Configured for PurgeCSS
            name: 'styles',
            test: /\.css$/,
            chunks: 'all',
            enforce: true,
          },
        },
      },
      // add optimizations rules for production here
    },
  };

  /**
   * Plugins
   */
  const plugins = [
    ...Base.plugins,
    // ...[
    //   new PurgecssPlugin({
    //     // Scans files and removes unused CSS
    //     paths: glob.sync(projectOptions.projectCss.purgeCss.paths, {
    //       nodir: true,
    //     }),
    //   }),
    //   // add plugins for production here
    // ],
  ];

  /**
   * Add sourcemap for production if enabled
   */
  const sourceMap = { devtool: false };
  if (
    projectOptions.projectSourceMaps.enable === true &&
    (projectOptions.projectSourceMaps.env === 'prod' ||
      projectOptions.projectSourceMaps.env === 'dev-prod')
  ) {
    sourceMap.devtool = projectOptions.projectSourceMaps.devtool;
  }

  /**
   * The configuration that's being returned to Webpack
   */
  return {
    mode: 'production',
    entry: projectOptions.projectJs.entry, // Define the starting point of the application.
    output: {
      path: projectOptions.projectOutput,
      filename: projectOptions.projectJs.filename,
    },
    devtool: sourceMap.devtool,
    optimization: optimizations,
    module: { rules: [cssRules, jsRules, imageRules, fontRules] },
    plugins,
  };
};
dayneh88 commented 3 years ago

@esalexreyes thanks for sending this over. so I've updated all of my webpack configs to match what you sent over. run yarn:dev watch and still getting this console error:

ERROR in ./assets/src/sass/app.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/css-loader/dist/cjs.js):

Do I need to update the actual @font-face declaration? Or change the filename of the font files?

Here is a screenshot of my VS: https://ibb.co/m0hyvQJ

We are close! Thanks again for your help mate

dayneh88 commented 3 years ago

@esalexreyes hey mate, just following up on my last question? I'm still having issues. Any help would be greatly appreciated. Thanks

dayneh88 commented 3 years ago

@esalexreyes I managed to get it working. It had to do with my paths in my @font-face. Thanks so much for your help again. Really got me out of a pickle

esalexreyes commented 3 years ago

@dayneh88 Sorry for my late reply! Glad you got it working! :)