nickjj / manifest-revision-webpack-plugin

Write out a manifest file containing your versioned webpack chunks and assets.
ISC License
124 stars 40 forks source link

include additional assets in manifest.json with webpack v4 #44

Closed nstoik closed 6 years ago

nstoik commented 6 years ago

I am using the plugin along with flask-webpack. Everything has been working great when using the

{{ stylesheet_tag('main_css') | safe }} or {{ javascript_tag('main_js') | safe }} tags. But whenever I try to use {{ asset_url_for('img\favicon.ico') }} or any other asset_url_for tag, it always resolves to None.

After some debugging, I discovered that those tags are not present in the generated manifest.json file (although it appears that webpack is seeing them as the file names appear in the console when running the webpack dev server).

Is there some configuration needed to get this working? Let me know if I should share any configuration files. I am using Webpack 4 but I am not sure if this is related, as the .js and .css assets are working.

Thanks.

nickjj commented 6 years ago

What does your webpack config look like?

nstoik commented 6 years ago

I started with a Flask Cookiecutter template that had a starter webpack config, and then tweaked it a little bit.

Do I have to add another entry point for images? So far I have just been calling them in my jinja2 templates using the {{ asset_url_for() }} tag.

Here is the config.

const path = require('path');
const webpack = require('webpack');

/*
 * Webpack Plugins
 */
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ManifestRevisionPlugin = require('manifest-revision-webpack-plugin');

// take debug mode from the environment
const debug = (process.env.NODE_ENV !== 'production');

// Development asset host (webpack dev server)
const publicHost = debug ? 'http://192.168.2.105:2992' : '';

const rootAssetPath = path.join(__dirname, 'assets');

module.exports = {
  // configuration
  context: __dirname,
  entry: {
    main_js: './assets/js/main',
    main_css: [
      path.join(__dirname, 'node_modules', 'font-awesome', 'css', 'font-awesome.css'),
      path.join(__dirname, 'node_modules', 'bootstrap', 'dist', 'css', 'bootstrap.css'),
      path.join(__dirname, 'node_modules', 'malihu-custom-scrollbar-plugin', 'jquery.mCustomScrollbar.css'),
      path.join(__dirname, 'assets', 'css', 'style.css'),
      path.join(__dirname, 'assets', 'css', 'nav-style.css'),
    ],
  },
  output: {
    path: path.join(__dirname, 'fm_frontend', 'static', 'build'),
    publicPath: `${publicHost}/static/build/`,
    filename: '[name].[hash].js',
    chunkFilename: '[id].[hash].js',
  },
  resolve: {
    extensions: ['.js', '.jsx', '.css'],
    alias:{
      img: path.join(__dirname, 'assets', 'img')
    },
  },
  devtool: 'source-map',
  devServer: {
    headers: { 'Access-Control-Allow-Origin': '*' },
  },
  module: {
    rules: [
      { test: /\.html$/, loader: 'raw-loader' },
      { test: /\.less$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader!less-loader' }) },
      { test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) },
      { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
      { test: /\.(ttf|eot|svg|png|jpe?g|gif|ico)(\?.*)?$/i, loader: 'file-loader?context=${rootAssetPath}&name=[path][name].[hash].[ext]' },
      { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', query: { presets: ['env'], cacheDirectory: true } },
    ],
  },
  plugins: [
    new ExtractTextPlugin('[name].[hash].css'),
    new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }),
    new ManifestRevisionPlugin(path.join(__dirname, 'fm_frontend', 'webpack', 'manifest.json'), {
      rootAssetPath,
      ignorePaths: ['/js', '/css'],
    }),
  ].concat(debug ? [] : [
    // production webpack plugins go here
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('production'),
      }
    }),
  ]),
};

And here is the generated manifest.json

{
    "assets": {
        "main_css.js": "main_css.d7c848c491f006d2119f.js",
        "main_css.css": "main_css.d7c848c491f006d2119f.css",
        "main_css.map": "main_css.d7c848c491f006d2119f.css.map",
        "main_js.js": "main_js.d7c848c491f006d2119f.js",
        "main_js.map": "main_js.d7c848c491f006d2119f.js.map"
    },
    "publicPath": "http://192.168.2.105:2992/static/build/"
}
nickjj commented 6 years ago

Here's an example config from the test Flask app:

var path = require('path');

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ManifestRevisionPlugin = require('manifest-revision-webpack-plugin');

var rootAssetPath = './assets';

module.exports = {
    entry: {
        app_js: [
            rootAssetPath + '/scripts/entry.js'
        ],
        app_css: [
            rootAssetPath + '/styles/main.css'
        ]
    },
    output: {
        path: './build/public',
        publicPath: 'http://localhost:2992/assets/',
        filename: '[name].[chunkhash].js',
        chunkFilename: '[id].[chunkhash].js'
    },
    resolve: {
        extensions: ['', '.js', '.css']
    },
    module: {
        loaders: [
            {
                test: /\.js$/i, loader: 'script-loader',
                exclude: /node_modules/
            },
            {
                test: /\.css$/i,
                loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
            },
            {
                test: /\.(jpe?g|png|gif|svg([\?]?.*))$/i,
                loaders: [
                    'file?context=' + rootAssetPath + '&name=[path][name].[hash].[ext]',
                    'image?bypassOnDebug&optimizationLevel=7&interlaced=false'
                ]
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin('[name].[chunkhash].css'),
        new ManifestRevisionPlugin(path.join('build', 'manifest.json'), {
            rootAssetPath: rootAssetPath,
            ignorePaths: ['/styles', '/scripts']
        })
    ]
};

I haven't upgraded to Webpack 4 yet, so I'm not sure if it does anything different to resolve assets.

nstoik commented 6 years ago

It looks to me like the problem is related to using Webpack 4. When I run "NODE_ENV=production webpack --progress --colors -p --mode production" , with either of the configs, all of the assets arrive in the output directory, they are just missing in the manifest file.

I will try dig deeper and see if I can figure it out. However I am more comfortable with Python than Javascript. Any suggestion where to start? Could it be something with the format option?

nstoik commented 6 years ago

So I was able to get this working by adding extensionsRegex: /\.(ico)(\?.*)?$/i to the ManifestRevisionPlugin configuration options.

Is this a always a required part of the configuration options? Do all assets that need to be included in the manifest.json file need to be either a Webpack entry point or be matched as part of the extensionsRegex?

nickjj commented 6 years ago

That wasn't always necessary, must be something new with webpack 4. In 2.x it would just pickup everything in the root path you supply (unless you ignored the path).

nstoik commented 6 years ago

It looks to be working now by explicitly including folders with desired assets via the extensionsRegex setting.

Thanks for the assistance! I really like the plugin

nickjj commented 6 years ago

No problem, thanks for the feedback. It's good to know things are working pretty well with 4.x.