Laravel-mix: Mix.extract compile empty CSS

Created on 12 Apr 2019  路  8Comments  路  Source: JeffreyWay/laravel-mix

  • Laravel Mix Version: 4.0.15
  • Node Version (node -v): 10.7.0
  • NPM Version (npm -v): 6.5.0
  • OS:

Description:

If i use extract with .sass at the exit i get empty css file, in the second case i compile without extract, as a result => all Okey

I have`t dynamic import in project

Steps To Reproduce:

First step: yarn watch
npm script node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js

webpack.mix.js
mix.setPublicPath(path.normalize('themes/frontend/assets'));
.sass('themes/frontend/assets/sass/style.scss', 'dist/css') .sass('themes/frontend/assets/sass/utils/_typografy.scss', 'dist/css') .js('themes/frontend/assets/js/main.js', 'dist/js/') .js('plugins/gotorussia/travels/assets/form.js', 'dist/experimental') .js('themes/frontend/assets/js/map.js', 'dist/js/');

Case 1 (without extract) result:
Asset Size Chunks Chunk Names
/dist/experimental/form.js 527 KiB /dist/experimental/form [emitted] /dist/experimental/form
/dist/js/main.js 7.66 MiB /dist/js/main [emitted] /dist/js/main
/dist/js/map.js 4.24 KiB /dist/js/map [emitted] /dist/js/map
dist/css/_typografy.css 270 KiB /dist/js/main [emitted] /dist/js/main
dist/css/style.css 542 KiB /dist/js/main [emitted] /dist/js/main

Case 2 (with extract()) result:

                 Asset       Size                            Chunks             Chunk Names
                                      /dist/js/manifest.js   11.5 KiB                 /dist/js/manifest  [emitted]  /dist/js/manifest
                                   dist/css/_typografy.css   15 bytes  /dist/js/main, /dist/js/manifest  [emitted]  /dist/js/main, /dist/js/manifest
                                        dist/css/style.css   15 bytes  /dist/js/main, /dist/js/manifest  [emitted]  /dist/js/main, /dist/js/manifest

Inside dist/css/style.css and /dist/js/manifest.js written: /* (ignored) */

Case 3 (with extract(['vue'])) result:

CSS empty

                                            Asset       Size                                             Chunks             Chunk Names
                                                                 /dist/js/manifest.js   11.9 KiB                                  /dist/js/manifest  [emitted]  /dist/js/manifest
                                                              dist/css/_typografy.css    0 bytes  /dist/js/main, /dist/js/manifest, /dist/js/vendor  [emitted]  /dist/js/main, /dist/js/manifest, /dist/js/ven
dor
                                                                   dist/css/style.css    0 bytes  /dist/js/main, /dist/js/manifest, /dist/js/vendor  [emitted]  /dist/js/main, /dist/js/manifest, /dist/js/ven
dor
stale

Most helpful comment

I was able to resolve this with a much easier workaround thanks to @escael

There's no need for 2 webpack.mix.js files.

In my project, I was able to modify it as the following:

mix.webpackConfig({
    entry: {
        main: ['./resources/sass/app.scss']
    }
});

All 8 comments

also experiencing same issue. any resolution to this. Extract without specifying vendor packs results in an empty .css; If i specify vendor packs, .css results with "__webpack_require__" calls to specified vendor packs.

any solution ?

My solution..., build your own webpack:

/webpack.config.json

const os = require('os')
const path = require('path')
const chalk = require('chalk')
const notifier = require('node-notifier')
const TerserPlugin = require('terser-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const BuildNotifierPlugin = require('webpack-build-notifier')
const ManifestPlugin = require('webpack-manifest-plugin')
const { VueLoaderPlugin } = require('vue-loader')
const WebpackBundleAnalyzer = require('webpack-bundle-analyzer')
const BundleAnalyzerPlugin = WebpackBundleAnalyzer.BundleAnalyzerPlugin
const pkg = require('./package.json')

module.exports = (env, argv) => {
  const appName = 'Webserver'
  const appLogo = path.resolve(__dirname, 'public/img/icon.png')
  const dist = path.resolve(__dirname, 'public/dist')
  const cache = path.resolve(__dirname, '.cache')
  const platform = os.platform()
  const developerName = os.userInfo().username
  const ENV = argv.mode ? argv.mode : env.NODE_ENV
  const isProd = ENV === 'production'
  const isDev = ENV === 'development'

  notifier.notify({
    appName: appName,
    title: appName,
    message: 'Starting webpack compiler...',
    contentImage: appLogo,
    sound: true,
    icon: path.resolve(__dirname, 'public/img/webpack.png'),
  })

  console.log('nodeENV:', chalk.whiteBright(ENV))
  console.log('whoIsMe:', chalk.whiteBright(developerName))
  console.log('whichOs:', chalk.whiteBright(platform))
  console.log('devMode:', isDev ? chalk.green(isDev) : chalk.red(isDev), '\n')

  return {
    entry: {
      app: './resources/js/app.js',
      style: './resources/sass/app.scss',
    },
    target: 'web',
    devtool: isDev ? 'cheap-module-eval-source-map' : 'source-map',
    output: {
      path: dist,
      filename: isDev ? '[name].js' : '[name].[chunkhash].js',
    },

    resolve: {
      alias: {
        vue: 'vue/dist/vue.js',
      },
    },

    optimization: {
      concatenateModules: true,
      // namedModules: true,
      // namedChunks: true,
      usedExports: true,
      runtimeChunk: 'single',
      splitChunks: {
        cacheGroups: {
          vendors: {
            test: /[\\/]node_modules[\\/]/,
            reuseExistingChunk: false,
            chunks: 'all',
            name: 'vendors',
          },
        },
      },
      minimize: isProd,
      minimizer: [
        new TerserPlugin({
          extractComments: 'some',
          sourceMap: false,
          cache: cache,
        }),
        new OptimizeCSSAssetsPlugin({
          cssProcessor: require('cssnano'),
          cssProcessorPluginOptions: {
            preset: [
              'advanced',
              {
                autoprefixer: {
                  add: true,
                  browsers: ['> 1% in DE'],
                },
                discardComments: { removeAll: true },
              },
            ],
          },
        }),
      ],
    },

    plugins: [
      new VueLoaderPlugin(),
      new CleanWebpackPlugin({
        cleanOnceBeforeBuildPatterns: [dist],
      }),
      new ManifestPlugin(),
      new BundleAnalyzerPlugin({
        analyzerMode: 'static',
        reportFilename: path.resolve(
          __dirname,
          `reports/${pkg.version}/treemap.html`
        ),
        openAnalyzer: false,
        logLevel: 'error',
        defaultSizes: 'gzip',
      }),
      new BuildNotifierPlugin({
        title: appName,
        logo: appLogo,
        suppressCompileStart: false,
        sound: true,
      }),
      new MiniCssExtractPlugin({
        filename: isDev ? '[name].css' : '[name].[chunkhash].css',
      }),
    ],

    stats: {
      hash: false,
      version: false,
      timings: false,
      children: false,
      errorDetails: false,
      entrypoints: false,
      performance: isProd,
      chunks: false,
      modules: false,
      reasons: false,
      source: false,
      publicPath: false,
      builtAt: false,
    },

    performance: {
      hints: false,
    },

    module: {
      rules: [
        {
          test: /\.vue$/,
          use: 'vue-loader',
        },
        {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          options: {
            presets: [['@babel/preset-env', { modules: false }]],
          },
        },
        {
          test: /\.s?(c|a)ss$/,
          use: [
            MiniCssExtractPlugin.loader,
            {
              loader: 'css-loader',
              options: {
                sourceMap: isDev,
                importLoaders: 1,
              },
            },
            {
              loader: 'sass-loader',
              options: {
                sourceMap: isDev,
              },
            },
          ],
        },
        {
          test: /\.(jpe?g|png|gif|svg|webp)$/i,
          use: [
            {
              loader: 'file-loader',
              options: {
                name: isDev ? '[name].[ext]' : '[name].[hash].[ext]',
                outputPath: 'images/',
              },
            },
          ],
        },
        {
          test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
          use: [
            {
              loader: 'file-loader',
              options: {
                name: isDev ? '[name].[ext]' : '[name].[hash].[ext]',
                outputPath: 'fonts/',
              },
            },
          ],
        },
      ],
    },
  }
}

/package.json

...
"scripts":
    "dev": "webpack --mode development --progress",
    "prod": "webpack --mode production --hide-modules",
...

/app/helpers.php

<?php

use App\Manifest;

if (!function_exists('manifest')) {
    function manifest($path)
    {
        return app(Manifest::class)(...func_get_args());
    }
}

/app/Manifest.php

<?php

namespace App;

use Exception;
use Illuminate\Support\HtmlString;

class Manifest
{
    public function __invoke($path)
    {
        static $manifestDirectory = '/dist/';

        $manifestPath = public_path($manifestDirectory . 'manifest.json');

        if (!file_exists($manifestPath)) {
            throw new Exception('The manifest file does not exist.');
        }

        $manifest = json_decode(file_get_contents($manifestPath), true);

        if (!isset($manifest[$path])) {
            throw new Exception("Unable to locate file: {$path}");
        }

        return new HtmlString($manifestDirectory . $manifest[$path]);
    }
}

Compiled files should be in /public/dist/. Now replace {{ mix('js/runtime.js') }} with {{ manifest('runtime.js') }}.

EDIT: just tested with vue and works fine

A work around for this, is to separate webpack.mix.js into different files ( so that each file has its own mix instance) :
You can name your files as webpack.css.mix.js and webpack.js.mix.js

webpack.css.mix.js

mix
.setPublicPath(path.normalize('themes/frontend/assets'))
.sass('themes/frontend/assets/sass/style.scss', 'dist/css') 
.sass('themes/frontend/assets/sass/utils/_typografy.scss', 'dist/css') ;

webpack.js.mix.js

mix
.setPublicPath(path.normalize('themes/frontend/assets'))
.js('themes/frontend/assets/js/main.js', 'dist/js/') 
.js('plugins/gotorussia/travels/assets/form.js', 'dist/experimental') 
.js('themes/frontend/assets/js/map.js', 'dist/js/');

And then you bulid them as follows:
for css: npm run dev --section=css
for js: npm run dev --section=js

Read here to know how to split and build your files.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

I was able to resolve this with a much easier workaround thanks to @escael

There's no need for 2 webpack.mix.js files.

In my project, I was able to modify it as the following:

mix.webpackConfig({
    entry: {
        main: ['./resources/sass/app.scss']
    }
});

I was able to resolve this with a much easier workaround thanks to @escael

There's no need for 2 webpack.mix.js files.

In my project, I was able to modify it as the following:

mix.webpackConfig({
    entry: {
        main: ['./resources/sass/app.scss']
    }
});

Thanks. Worked like magic. Kindly point us to what @escael said so I can understand better what is going on and why it works.

I was able to resolve this with a much easier workaround thanks to @escael
There's no need for 2 webpack.mix.js files.
In my project, I was able to modify it as the following:

mix.webpackConfig({
    entry: {
        main: ['./resources/sass/app.scss']
    }
});

Thanks. Worked like magic. Kindly point us to what @escael said so I can understand better what is going on and why it works.

I think #1887 (comment) is the comment @mikesaintsg was referring to.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mementoneli picture mementoneli  路  3Comments

jpmurray picture jpmurray  路  3Comments

mstralka picture mstralka  路  3Comments

RomainGoncalves picture RomainGoncalves  路  3Comments

kpilard picture kpilard  路  3Comments