Как избавиться от упаковщиков веб-пакетов и получить упрощенный минимизированный код ES5 IIFE при объединении приложения AngularJS - PullRequest
0 голосов
/ 03 июля 2019

Я использую babel v6.x и webpack v2.x для переноса кода ES6, а также для сборки и объединения всего кода приложения (конфиги ниже). Приложение предназначено в первую очередь для IE11 и будет работать во внутренней сети клиента.

Я также использую некоторые заливки ES6 для IE11.

Проблема в том, что код, созданный даже для производственной среды, по-прежнему помещается в оболочку webpackJsonp и организуется в виде модулей.

То, чего я хотел бы добиться, - это пакет приложения .js и пакет кода стороннего поставщика, который полностью переносится в ES5 IIFE, минимизируется и расширяется, без каких-либо оболочек или секций на модули.

Лучше всего, если бы я мог получить этот результат также для кода, обслуживаемого webpack-dev-server, а не только для окончательной сборки dist приложения.

Таким образом, в основном, код результата должен быть ES5 IIFE, сохраненным в *.min.js файлах. Зачем? Потому что я собираюсь использовать webpack только во время сборки и комплектации, а не все время и только тогда.

Я хотел бы отметить, что текущие документы веб-пакетов переписаны для использования в основном с веб-пакетом v4, поэтому не все понятно для моего v2.

Как мне этого добиться?

webpack.config.js:

var path    = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var execSync = require('child_process').execSync;

module.exports = function (env) {
  var appSettings = require(path.join(__dirname, 'client/settings.js'));
  var indexFile = 'client/index.html';

  var revisionHash = execSync('git rev-parse HEAD').toString().trim().substring(0, 6);
  var revisionCount = execSync('git rev-list --count HEAD').toString().trim();
  var buildDate = new Date().toISOString();
  var revision = revisionHash + ' (' + revisionCount + ') built on ' + buildDate;

  return {
    entry: {},
    target: "node",
    module: {
      rules: [
        {
          test: /\.js$/,
          include: [/client/, path.resolve(__dirname, 'node_modules/core-web')],
          use: [
            'ng-annotate-loader',
            {
              loader: 'babel-loader',
              options: {
                presets: [['env', {
                  "targets": {
                    "ie": "11"
                  }
                }]]
              }
            }
          ]
        },
        {
          test: /\.(png|jpg|jpeg|gif|html|json|pdf|csv)$/,
          loader: 'file-loader',
          options: {
            publicPath: '/'
          }
        },
        {
          test: /\.(jar|xml|dll)$/,
          loader: 'file-loader',
          options: {
            publicPath: '/',
            name: '[name].[ext]'
          }
        },
        {
          test: /\.(eot|svg|ttf|woff(2)?)(\?v=\d+\.\d+\.\d+)?/,
          loader: 'file-loader',
          options: {
            publicPath: '/'
          }
        },
        {
          test: /\.less$/,
          loader: ExtractTextPlugin.extract({
            fallbackLoader: 'style-loader',
            loader: ['css-loader', 'postcss-loader', 'less-loader'],
            publicPath: path.resolve(__dirname, 'dist')
          })
        },
        {
          test: /\.css$/,
          loader: ExtractTextPlugin.extract({
            fallbackLoader: 'style-loader',
            loader: ['css-loader', 'postcss-loader'],
            publicPath: path.resolve(__dirname, 'dist')
          })
        }
      ]
    },
    resolve: {
      modules: [
        'node_modules',
        path.resolve(__dirname)
      ],
      alias: {
        common: 'client/app/common',
        img: 'client/app/common/static/img'
      }
    },
    plugins: [
      new ExtractTextPlugin('[name].[hash].css'),
      // Injects bundles in your index.html instead of wiring all manually.
      // It also adds hash to all injected assets so we don't have problems
      // with cache purging during deployment.

      new HtmlWebpackPlugin({
        template: indexFile,
        favicon: 'client/app/common/static/favicon.ico',
        inject: 'body',
        hash: true
      }),

      new webpack.DefinePlugin({
        __API_URL__: JSON.stringify(appSettings[env] || ''),
        __REVISION__: JSON.stringify(revision)
      }),

      // Automatically move all modules defined outside of application directory to vendor bundle.
      // If you are using more complicated project structure, consider to specify common chunks manually.
      new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        minChunks: function (module, count) {
          return module.resource && module.resource.indexOf(path.resolve(__dirname, 'client')) === -1;
        }
      }),

      new webpack.optimize.UglifyJsPlugin({})
    ]
  }
};

webpack.dev.config.js

var webpack = require('webpack');
var path    = require('path');
var config  = require('./webpack.config')('DEV');

config.output = {
  filename: '[name].bundle.js',
  publicPath: '/',
  path: path.resolve(__dirname, 'client')
};

config.plugins = config.plugins.concat([

  // Adds webpack HMR support. It act's like livereload,
  // reloading page after webpack rebuilt modules.
  // It also updates stylesheets and inline assets without page reloading.
  new webpack.HotModuleReplacementPlugin()
]);

module.exports = config;

webpack.dist.config.js

const webpack = require('webpack');
const path    = require('path');
const config  = require('./webpack.config')('PROD');
const yargs = require('yargs');

config.output = {
  filename: '[name].[hash].js',
  publicPath: '',
  path: path.resolve(__dirname, 'dist')
};

const plugins = [];

if(!yargs.argv.dev) {
  plugins.push(
    // Reduces bundles total size
    new webpack.optimize.UglifyJsPlugin({
      mangle: {

        // You can specify all variables that should not be mangled.
        // For example if your vendor dependency doesn't use modules
        // and relies on global variables. Most of angular modules relies on
        // angular global variable, so we should keep it unchanged
        except: ['$super', '$', 'exports', 'require', 'angular']
      }
    })
  );
}

config.plugins = config.plugins.concat(plugins);

module.exports = config;

gulpfile.babel.js

const gulp = require('gulp');
const webpack = require('webpack');
const path = require('path');
const rename = require('gulp-rename');
const template = require('gulp-template');
const yargs = require('yargs');
const gutil = require('gulp-util');
const serve = require('browser-sync');
const del = require('del');
const webpackDevMiddelware = require('webpack-dev-middleware');
const webpachHotMiddelware = require('webpack-hot-middleware');
const colorsSupported = require('supports-color');
const historyApiFallback = require('connect-history-api-fallback');
const generator = require('core-web/generator');
const camelCase = require('lodash/camelCase');
const zip = require('gulp-zip');
const moment = require('moment');

const root = 'client';

// helper method for resolving paths
const resolveToApp = (glob = '') => path.join(root, 'app', glob);
const resolveToComponents = (glob = '') => path.join(root, 'app/components', glob);

// map of all paths
const paths = {
  js: resolveToComponents('**/*!(.spec.js).js'), // exclude spec files
  less: resolveToApp('**/*.less'), // stylesheets
  html: [
    resolveToApp('**/*.html'),
    path.join(root, 'index.html')
  ],
  entry: {
    dev: path.join(__dirname, root, 'environments/dev.js'),
    uat: path.join(__dirname, root, 'environments/uat.js'),
    prod: path.join(__dirname, root, 'environments/prod.js')
  },
  polyfill: path.join(__dirname, root, 'app/common/vendors/polyfill/polyfill.js'),
  output: root,
  blankTemplates: path.join(__dirname, path.relative(__dirname, generator), 'component/**/*.**'),
  dest: path.join(__dirname, 'dist')
};

const zipDist = () => {
  const now = moment().format('YYYYMMDDHHmm');
  const zipName = 'app_' + now + '.zip';

  gulp
    .src('dist/**/*', { dot: true })
    .pipe(zip(zipName))
    .pipe(gulp.dest(paths.dest));
};

// use webpack.config.js to build modules
gulp.task('webpack', ['clean'], cb => {
  const config = require('./webpack.dist.config');
  config.entry.app = yargs.argv.uat ? paths.entry.uat : paths.entry.prod;
  config.entry.polyfill = paths.polyfill;

  if (yargs.argv.uat) {
    config.devtool = 'eval-source-map';
  }

  webpack(config, (err, stats) => {
    if (err) {
      throw new gutil.PluginError('webpack', err);
    }

    gutil.log('[webpack]', stats.toString({
      colors: colorsSupported,
      chunks: false,
      errorDetails: true
    }));

    gulp
      .src('./.htaccess')
      .pipe(gulp.dest(paths.dest))
      .on('data', () => {
        zipDist();
      });

    cb();
  });
});

gulp.task('serve', () => {
  const config = require('./webpack.dev.config');
  config.entry.app = [
    // this modules required to make HRM working
    // it responsible for all this webpack magic
    'webpack-hot-middleware/client?reload=true',
    // application entry point
    paths.entry.dev,
    paths.polyfill
  ];
  config.devtool = 'eval-source-map';

  const compiler = webpack(config);

  serve({
    port: process.env.PORT || 3000,
    open: false,
    server: { baseDir: root },
    middleware: [
      historyApiFallback(),
      webpackDevMiddelware(compiler, {
        stats: {
          colors: colorsSupported,
          chunks: false,
          modules: false
        },
        publicPath: config.output.publicPath
      }),
      webpachHotMiddelware(compiler)
    ]
  });
});

gulp.task('watch', ['serve']);

gulp.task('component', () => {
  const cap = val => {
    return val.charAt(0).toUpperCase() + val.slice(1);
  };
  const name = yargs.argv.name;
  const parentPath = yargs.argv.parent || '';
  const destPath = path.join(resolveToComponents(), parentPath, name);

  return gulp.src(paths.blankTemplates)
    .pipe(template({
      name,
      upCaseName: cap(name),
      parent: parentPath,
      fullName: camelCase(parentPath + ' ' + name)
    }))
    .pipe(rename(dir => {
      dir.basename = dir.basename.replace('temp', name);
    }))
    .pipe(gulp.dest(destPath));
});

gulp.task('clean', cb => {
  del([paths.dest]).then(dir => {
    gutil.log('[clean]', dir);
    cb();
  });
});

gulp.task('default', ['watch']);

.babelrc

{
  "presets": [['env', {
    "targets": {
      "ie": "11"
    }
  }]]
}
...