后端Webpack与Vue-CLI 3集成

时间:2019-03-03 03:38:36

标签: vue.js

我正在使用Vue-CLI 3开发全栈应用程序。后端是用TypeScript编写的,因此需要进行编译等。目前,我只是使用ts-node直接运行可以正常工作的后端应用程序,但是它如果我还可以将后端应用程序打包成一个server.js,而不是到处都是多个散乱的打字稿文件,那将更加干净。

问题在于,我通常这样做的方法是只有一个webpack.base.js,然后将其包含在不同的webpack配置文件中。我真的不能这样做,因为vue-cli-service

中隐藏了许多Webpack配置

1 个答案:

答案 0 :(得分:0)

最终获得了基本的 webpack 配置并扩展了客户端和服务器 webpack 配置。

我的应用根目录 webpack.config.js 如下所示:

const { config: client } = require('./src/client/webpack.config');
const { config: server } = require('./src/server/webpack.config');

/**
 * Webpack Build File
 *
 * This webpack configuration is used for only building the client and server
 * bundles. It imports both of these from their respective directories, but
 * allows for overrides if required.
 *
 * Other dev tools such as watching, hot module reloading etc. has been split
 * out into other config files
 *
 * @param {object} env Webpack `env` object
 */
module.exports = ({ mode = 'development' } = {}) => ([
  {
    ...client({ mode }, process.env),
  },
  {
    ...server({ mode }, process.env),
  },
]);

我的 src/client/webpack.config.js 看起来像这样:

const { resolve: _resolve, sep } = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TSConfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackRootElementPlugin = require('html-webpack-root-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const { DefinePlugin } = require('webpack');

const paths = {
  src: {
    rootDir: _resolve(__dirname) + sep,
    app: _resolve(__dirname, 'app') + sep,
  },
  dist: {
    rootDir: _resolve(__dirname, '..', '..', 'dist'),
    app: _resolve(__dirname, '..', '..', 'dist', 'public'),
  },
};

/**
 * Client webpack build configuration.
 *
 * This webpack config produces a bundle for the client-side application only.
 *
 * @param {object} webpackEnv Webpack env object (basically any/all options passed in via the CLI)
 * @param {object} processEnv Process env object (environment variables from process.env)
 */
const config = ({ mode = 'none' }, { APP_NAME = '', BASE_URL = '/' } = {}) => ({
  name: 'client',
  target: 'web',
  mode,
  entry: {
    app: paths.src.app + 'main.ts',
  },
  output: {
    path: paths.dist.app,
  },
  optimization: {
    runtimeChunk: 'single',
  },
  resolve: {
    extensions: ['.ts', '.js', '.vue'],
    plugins: [
      new TSConfigPathsPlugin({
        configFile: paths.src.rootDir + 'tsconfig.json',
      }),
    ],
  },
  context: paths.src.rootDir,
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        include: paths.src.rootDir,
        exclude: /node_modules/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              happyPackMode: true,
            },
          },
        ],
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.s?[ac]ss$/,
        use: [
          'style-loader',
          'css-loader',
          'sass-loader',
        ],
      },
      {
        test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/i,
        loader: 'file-loader',
        options: {
          name: 'assets/[name].[hash].[ext]',
          esModule: false,
        },
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      favicon: paths.src.app + 'assets/logo.png',
      title: APP_NAME,
    }),
    new HtmlWebpackRootElementPlugin('app'),
    new VueLoaderPlugin(),
    new DefinePlugin({
      'process.env.BASE_URL': JSON.stringify(BASE_URL),
    }),
  ],
});

module.exports = {
  config,
  paths,
};

我的 src/server/webpack.config.js 看起来像这样:

const { resolve: _resolve, sep } = require('path');
const TSConfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
const { IgnorePlugin } = require('webpack');

const paths = {
  src: _resolve(__dirname) + sep,
  dist: _resolve(__dirname, '..', '..', 'dist'),
};

/**
 * NestJs uses a custom wrapper around require() that allows it to show a
 * warning when some extra package needs to be installed. This causes problems
 * with webpack, so we're blacklisting packages we're not using with the
 * IgnorePlugin below.
 *
 * To de-blacklist a package, just remove it from this array.
 */
const nestBlacklist = [
  '^cache-manager$',
  '^@nestjs/microservices$',
  // packages below are required from microservices
  '^amqp-connection-manager$',
  '^amqplib$',
  '^grpc$',
  '^mqtt$',
  '^nats$',
  '^redis$',
];

/**
 * Server webpack build configuration.
 *
 * This webpack config produces a bundle for the server-side application only.
 *
 * @param {object} webpackEnv Webpack env object (basically any/all options passed in via the CLI)
 * @param {object} processEnv Process env object (environment variables from process.env)
 */
const config = ({ mode = 'none' }) => ({
  name: 'server',
  mode,
  target: 'node',
  entry: paths.src + 'main.ts',
  externals: [nodeExternals()],
  output: {
    path: paths.dist,
    filename: 'server.js',
  },
  resolve: {
    extensions: ['.ts', '.js'],
    plugins: [
      new TSConfigPathsPlugin({
        configFile: './tsconfig.build.json',
      }),
    ],
  },
  context: paths.src,
  optimization: {
    minimize: false,
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.ts$/,
        include: paths.src,
        exclude: /node_modules/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              happyPackMode: true,
            },
          },
        ],
      },
    ],
  },
  plugins: [
    new IgnorePlugin({
      contextRegExp: /@nestjs/,
      resourceRegExp: new RegExp(nestBlacklist.join('|')),
    }),
  ],
  node: {
    __dirname: false,
  },
});

module.exports = {
  config,
  paths,
};

这允许我拥有不同的服务器端和客户端编译配置,但这种方式可以在其他配置中重用。因此,对于 webpack 开发服务器 - 我有 webpack.dev.config.js,其中包含以下内容:

const client = require('./src/client/webpack.config');
const server = require('./src/server/webpack.config');
const { HotModuleReplacementPlugin } = require('webpack');

const {
  SERVER_PORT = 3000,
} = process.env;

/**
 * Watch settings are the same between client and server, so we're keeping them
 * here for consistency
 */
const watchConfig = {
  watch: true,
  watchOptions: {
    ignored: /node_modules/,
  },
};

/**
* Development Webpack Build File
*
* This webpack configuration extends `webpack.config.js` and builds on it to
* provide hot module replacement, watch moide and a dev server for the
* client-side code
*
* Other dev tools such as watching, hot module reloading etc. has been split
* out into other config files
*
* @param {object} env Webpack `env` object
*/
module.exports = ({ mode = 'development' } = {}) => ([
  {
    ...client.config({ mode }, process.env),
    ...watchConfig,
    devServer: {
      contentBase: client.paths.dist.app,
      historyApiFallback: {
        rewrites: [
          { from: /./, to: '/index.html' },
        ],
      },
      port: 8000,
      host: '0.0.0.0',
      hot: true,
      hotOnly: true,
      proxy: {
        '/api': `http://localhost:${SERVER_PORT}/`,
      },
    },
  },
  {
    ...server.config({ mode }, process.env),
    ...watchConfig,
    plugins: [
      ...server.config({ mode }, process.env).plugins,
      new HotModuleReplacementPlugin(),
    ],
  },
]);

此配置提供了一个设置,它生成一个 server.js,然后提供一个目录(在本例中为“/public”),因为它是静态文件目录。