wang1dot0 / personal-note

记录工作中遇到的个人觉得比较有意思的小问题
https://github.com/wang1dot0/personal-note
0 stars 0 forks source link

webpack config #36

Open wang1dot0 opened 4 years ago

wang1dot0 commented 4 years ago

webpack.base.config.js

const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');

const NODE_ENV = process.env.NODE_ENV || 'development';
const isProd = NODE_ENV === 'production';

function resolve(dir) {
  return path.join(__dirname, '..', dir);
}

const cssLoader = [
  {
    loader: 'css-loader',
    options: { minimize: isProd },
  },
  'postcss-loader',
  'less-loader',
];

const webpackCommonPlugins = [
  new VueLoaderPlugin(),
  new MiniCssExtractPlugin({
    filename: 'common.[chunkhash].css',
  }),
  ...(isProd ? [] : [new FriendlyErrorsPlugin()]),
];

module.exports = {
  mode: NODE_ENV,
  devtool: isProd ? false : '#cheap-module-source-map',
  output: {
    path: resolve('dist'),
    publicPath: '/dist/',
    library: 'CONSOLE',
    jsonpFunction: 'CONSOLEJsonp',
    filename: '[name].[chunkhash].js',
  },
  externals: {
    jquery: 'jQuery',
  },
  resolve: {
    extensions: ['.webpack.js', '.web.js', '.ts', '.js', '.json', '.vue'],
    alias: {
      public: resolve('public'),
      jquery: resolve('public/js/jquery.min.js'),
      vue$: 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
  },
  module: {
    noParse: /es6-promise\.js$/,
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          compilerOptions: {
            preserveWhitespace: false,
          },
        },
      },
    ],
  },
  performance: {
    maxEntrypointSize: 300000,
    hints: isProd ? 'warning' : false,
  },
  plugins: webpackCommonPlugins,
};

webpack.client.config.js

const webpack = require('webpack');
const merge = require('webpack-merge');
const base = require('./webpack.base.config');
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin');

const config = merge(base, {
  entry: {
    app: './src/entry-client.js',
  },
  resolve: {
    alias: {
      'create-api': './create-api-client.ts',
      logger: './logger-client.ts',
    },
  },
  optimization: {
    runtimeChunk: {
      name: 'manifest',
    },
    splitChunks: {
      chunks: 'initial',
      cacheGroups: {
        vendor: {
          name: 'vendor',
          test(module) {
            return (
              /node_modules/.test(module.context) &&
              !/\.css$/.test(module.request)
            );
          },
        },
      },
    },
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
    }),
    // strip dev-only code in Vue source
    new webpack.DefinePlugin({
      'process.env.VUE_ENV': '"client"',
    }),
    new VueSSRClientPlugin(),
  ],
});

module.exports = config;

webpack.server.config.js

const webpack = require('webpack');
const merge = require('webpack-merge');
const base = require('./webpack.base.config');
const nodeExternals = require('webpack-node-externals');
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');

module.exports = merge(base, {
  target: 'node',
  devtool: '#source-map',
  entry: './src/entry-server.js',
  output: {
    filename: 'server-bundle.js',
    libraryTarget: 'commonjs2',
  },
  resolve: {
    alias: {
      'create-api': './create-api-server.ts',
      logger: './logger-server.ts',
    },
  },
  // https://webpack.js.org/configuration/externals/#externals
  // https://github.com/liady/webpack-node-externals
  externals: nodeExternals({
    // do not externalize CSS files in case we need to import it from a dep
    whitelist: /\.css$|vue-echarts/,
  }),
  plugins: [
    new webpack.DefinePlugin({
      'process.env.VUE_ENV': '"server"',
    }),
    new VueSSRServerPlugin(),
  ],
});

setup-dev-server.js

const path = require('path');
const webpack = require('webpack');
const MFS = require('memory-fs');
const clientConfig = require('./webpack.client.config');
const serverConfig = require('./webpack.server.config');

const readFile = (fs, file) => {
  try {
    return fs.readFileSync(path.join(clientConfig.output.path, file), 'utf-8');
  } catch (e) {}
};

module.exports = function setupDevServer(app, cb) {
  let bundle, clientManifest;
  let resolve;
  const readyPromise = new Promise(r => {
    resolve = r;
  });
  const ready = (...args) => {
    resolve();
    cb(...args);
  };

  // modify client config to work with hot middleware
  clientConfig.entry.app = ['webpack-hot-middleware/client', clientConfig.entry.app];
  clientConfig.output.filename = '[name].js';
  clientConfig.plugins.push(new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin());

  // dev middleware
  const clientCompiler = webpack(clientConfig);
  const devMiddleware = require('webpack-dev-middleware')(clientCompiler, {
    publicPath: clientConfig.output.publicPath,
    noInfo: true,
  });
  app.use(devMiddleware);
  clientCompiler.plugin('done', stats => {
    stats = stats.toJson();
    stats.errors.forEach(err => console.error(err));
    stats.warnings.forEach(err => console.warn(err));
    if (stats.errors.length) return;

    clientManifest = JSON.parse(readFile(devMiddleware.fileSystem, 'vue-ssr-client-manifest.json'));
    if (bundle) {
      ready(bundle, {
        clientManifest,
        inject: false,
      });
    }
  });

  // hot middleware
  app.use(require('webpack-hot-middleware')(clientCompiler));

  // watch and update server renderer
  const serverCompiler = webpack(serverConfig);
  const mfs = new MFS();
  serverCompiler.outputFileSystem = mfs;
  serverCompiler.watch({}, (err, stats) => {
    if (err) throw err;
    stats = stats.toJson();
    if (stats.errors.length) return;

    // read bundle generated by vue-ssr-webpack-plugin
    bundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json'));
    if (clientManifest) {
      ready(bundle, {
        clientManifest,
        inject: false,
      });
    }
  });

  return readyPromise;
};