3
"webpack": "^2.7.0"

I'm trying to add a hash to our translation files in order to cache bust when deploying. I've managed to extract the json and add a hash and output it to a folder and is good with the world.

But, my unhashed json is still under there original folders after building. I understand that we don't need to add a loader for json as it already has means of handling importing, so my question would be how do I clean out the json that's already been processed?

my folder structure is as follows

src/
   app/
     module-name/
        /translations
         en.json
         fn.json
     module-name/
        /translations
         en.json
         fn.json
     //ect...

I used the CopyWebpackPlugin to get the json and hash is there maybe an option ive missed that cleans out the process'd files? or maybe i'm approaching this the incorrect way.

const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');

const VersionFile = require('webpack-version-file');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const pkg = require('../package.json');
const autoprefixer = require('autoprefixer');

module.exports = {
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'eslint-loader',
        enforce: 'pre'
      },
      {
        test: /\.(css|scss)$/,
        loaders: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader?minimize!resolve-url-loader!sass-loader?sourceMap!postcss-loader'
        })
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        loader: 'file-loader',
        options: {
          regExp: /\/([a-z0-9]+)\/[a-z0-9]+\.json$/,
          name: '[name]-[hash].[ext]'
        }
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loaders: [
          'ng-annotate-loader',
          'babel-loader'
        ]
      },
      {
        test: /\.html$/,
        loaders: [
          'html-loader'
        ]
      }
    ]
  },
  plugins: [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new HtmlWebpackPlugin({
      template: conf.path.src('index.html')
    }),
    new webpack.optimize.UglifyJsPlugin({
      output: {comments: false},
      compress: {unused: true, dead_code: true, warnings: false} // eslint-disable-line camelcase
    }),
    new ExtractTextPlugin('index-[contenthash].css'),
    new webpack.optimize.CommonsChunkPlugin({name: 'vendor'}),
    new webpack.LoaderOptionsPlugin({
      options: {
        postcss: () => [autoprefixer]
      }
    }),
    new webpack.HashedModuleIdsPlugin(),
    new CopyWebpackPlugin([{
      from: 'src/app/**/*.json',
      to: 'translations/[name]-[hash].[ext]'
    }]),
    new VersionFile({
      output: `${conf.paths.dist}/version.txt`,
      verbose: true
    })
  ],
  output: {
    path: path.join(process.cwd(), conf.paths.dist),
    filename: '[name]-[hash].js'
  },
  entry: {
    app: [`./${conf.path.src('app/app.module.js')}`],
    vendor: Object.keys(pkg.dependencies)
  },
  node: {
    fs: 'empty',
    /* eslint-disable camelcase */
    child_process: 'empty'
  }
};

Or to similfy the question, how can i add a hash to json files? and the following code doesn't seem to do anything.

   {
       test: /\.json$/,
       loader: 'file-loader',
       options: {
         name: '[name]-[hash].[ext]'
       }
   }

example of the translations being in both locations

EDIT:

so it seems like my json loader doesnt pick up the translation files as they're dynamicly imported like so how:

  $translateProvider.useLoader('$translatePartialLoader', {
    urlTemplate: 'app/{part}/translations/{lang}.json'
  });

do you handle cases like this?

Joe Warner
  • 3,335
  • 1
  • 14
  • 41
  • In CopyWebpackPlugin you can specify the path `to: path.join(process.cwd(), conf.path.dist, 'translations/[name]-[hash].[ext]')` it will provide an absolute path to the plugin instead of the current relative path per entry. This will create a `translations` folder at the root of your dist directory – aquiseb Nov 13 '18 at 18:34
  • Yes I can create the translations folder with the hashes just fine will your method remove the old entries? – Joe Warner Nov 13 '18 at 19:08
  • @astenmies Thanks for having a look – Joe Warner Nov 13 '18 at 19:09
  • To remove the old entries you can just delete the dist folder and build again – aquiseb Nov 13 '18 at 19:10
  • No so the JSON copied still remains in there original path shown In the screen shot ofc I could do something like exec('-rm /dist/app') or something to that flavour but I was hoping it could be done with the build step if not that's cool – Joe Warner Nov 13 '18 at 19:13
  • There's an npm package called `rimraf` that does a `rm -rf`. You may use that to iterate over the files together with `fs` [see looping through files](https://stackoverflow.com/questions/32511789/looping-through-files-in-a-folder-node-js) – aquiseb Nov 13 '18 at 19:27

1 Answers1

2

The main goal you're trying to do here is telling the browser its a new file when releasing a new version and we can do this fairly easily without having to force webpack to know what files are being used.

in your webpack config add this

const pkg = require('../package.json');
//...
new webpack.DefinePlugin({
  __VERSION__: JSON.stringify(pkg.version)
})

and where you add your translation files this allows for the browser to know where has been a new release and should update translation files.

$translateProvider.useLoader('$translatePartialLoader', {
   urlTemplate: `app/{part}/translations/{lang}.json?v=${__VERSION__}`
});
Joe Warner
  • 3,335
  • 1
  • 14
  • 41