axe-me / vite-plugin-node

Vite plugin to run your node dev server with HMR!
1k stars 48 forks source link

Build for production? #20

Closed onekiloparsec closed 2 years ago

onekiloparsec commented 3 years ago

Hi. I've tried your plugin, as it seems my last chance of making my setup working. It seems really great, but I am not sure to understand how to use it for production.

I have a fairly sophisticated express.js-based backend, and I try to build into a custom folder dist-prod that I deploy to heroku. But I can't find how to run vite build and end up with the correct output.

As far as I understand, your plugin isn't ready to build for production, right? Anything I can do to help? Thanks a lot.

radiorz commented 2 years ago

if possible, I wish the vite could build nodejs to one file like webpack do. here is an example with webpack4:

'use strict';

const path = require('path');
let externals = _externals();

module.exports = {
  mode: 'production',
  entry: {
    app: './index.js'
  },
  target: 'node',
  output: {
    path: path.resolve('./build'),
    filename: '[name].cjs'
  },
  resolve: {
    extensions: ['.js']
  },
  externals: externals,
  node: {
    console: true,
    global: true,
    process: true,
    Buffer: true,
    __filename: true,
    __dirname: true,
    setImmediate: true
  },
  module: {},
  plugins: []
};

function _externals() {
  let manifest = require('./package.json');
  let dependencies = manifest.dependencies;
  let externals = {};
  for (let p in dependencies) {
    externals[p] = 'commonjs ' + p;
  }
  return externals;
}
taka1156 commented 2 years ago
import { defineConfig } from 'vite';
import { VitePluginNode } from 'vite-plugin-node';
import { resolve } from 'path';

export default defineConfig({
  root: 'src',
  server: {
    port: 3000,
  },
  build: {
    ssr: 'index.ts',
    outDir: '../api',
    emptyOutDir: true
  },
  plugins: [
    ...VitePluginNode({
      adapter: 'express',
      appPath: './src/index.ts',
      tsCompiler: 'esbuild',
    }),
  ],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
    },
  },
});

{
...
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
...
}
yarn build or npm run build

https://github.com/vitejs/vite/blob/5396a706ca21b9943e1c94d87192eeb4f03d3df5/packages/playground/ssr-vue/package.json#L10

https://github.com/taka1156/vite-express-sample

axe-me commented 2 years ago

I just released 0.0.17 to npm, please check it out.

Thanks @taka1156 for providing this solution. I added this ssr config to the plugin default, the plugin will just use the appPath as entry to build/bundle the app.

simply add a build script to your package.json, it should just work!

radiorz commented 2 years ago

@axe-me [bug] when I dont put the build/ssr option, the plugin will pass appPath to build/ssr. but when there is a root option in vite,it will be a mistake: image

taka1156 commented 2 years ago

@radiorz

import { defineConfig } from 'vite';
import { VitePluginNode } from 'vite-plugin-node';
import { resolve } from 'path';

export default defineConfig({
  root: 'src',
  server: {
    port: 3000,
  },
  build: {
    ssr: true,
    outDir: '../api',
    emptyOutDir: true
  },
  plugins: [
    ...VitePluginNode({
      adapter: 'express',
      appPath: process.env.NODE_ENV ==='production' ? 'index.ts' : 'src/index.ts',
      tsCompiler: 'esbuild',
    }),
  ],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
    },
  },
});

https://github.com/taka1156/vite-express-sample/tree/update-vite-plugin-node

radiorz commented 2 years ago

@radiorz

import { defineConfig } from 'vite';
import { VitePluginNode } from 'vite-plugin-node';
import { resolve } from 'path';

export default defineConfig({
  root: 'src',
  server: {
    port: 3000,
  },
  build: {
    ssr: true,
    outDir: '../api',
    emptyOutDir: true
  },
  plugins: [
    ...VitePluginNode({
      adapter: 'express',
      appPath: process.env.NODE_ENV ==='production' ? 'index.ts' : 'src/index.ts',
      tsCompiler: 'esbuild',
    }),
  ],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
    },
  },
});

https://github.com/taka1156/vite-express-sample/tree/update-vite-plugin-node

thanks, this is a way to solve my problem.

saiqulhaq commented 2 years ago

I think we need to update the README there is a statement on TODO section that this tool doesn't have build command for docker

taka1156 commented 2 years ago
import { Plugin, UserConfig, ConfigEnv } from 'vite';
import { PLUGIN_NAME, ViteConfig, VitePluginNodeConfig } from '.';
import { RollupPluginSwc } from './rollup-plugin-swc';
import { createMiddleware } from './server';

export function VitePluginNode(cfg: VitePluginNodeConfig): Plugin[] {
  const config: VitePluginNodeConfig = {
    appPath: cfg.appPath,
    adapter: cfg.adapter,
    tsCompiler: cfg.tsCompiler ?? 'esbuild',
    exportName: cfg.exportName ?? 'viteNodeApp'
  };

  const resolvePath = (root: string = '', config: VitePluginNodeConfig): VitePluginNodeConfig => {
    if (root !== '') {
      config.appPath = `${root}/${config.appPath}`;
    }
    return config;
  };

  const resolveConfig = (viteConfig: UserConfig, env: ConfigEnv ): ViteConfig => {

    const { root, build } = viteConfig;
    const { appPath } = config;

    if (env.mode === 'serve') {
      // serve
      return {
        // https://vitejs.dev/config/#root
        root: root || process.cwd(),
        server: {
          hmr: false
        },
        esbuild: config.tsCompiler === 'esbuild' ? {} : false,
        VitePluginNodeConfig: resolvePath(root, config),
      };
    } else {
      // build
      return {
        // https://vitejs.dev/config/#root
        root: root || process.cwd(),
        build: {
          ssr: appPath || 'index.js', // production entry point
          outDir: build?.outDir || '../dist',
          emptyOutDir: build?.emptyOutDir|| true,
        },
        esbuild: config.tsCompiler === 'esbuild' ? {} : false,
        VitePluginNodeConfig: resolvePath(root, config)
      };
    }
  };

  const plugins: Plugin[] = [
    {
      name: PLUGIN_NAME,
      config: (viteConfig, env) => resolveConfig(viteConfig, env),
      configureServer: (server) => {
        server.middlewares.use(createMiddleware(server));
      },
      apply: 'serve'
    },
    {
      name: PLUGIN_NAME,
      config: (viteConfig, env) => resolveConfig(viteConfig, env),
      apply: 'build'
    }
  ];

  if (config.tsCompiler === 'swc') {
    plugins.push({
      ...RollupPluginSwc({
        jsc: {
          target: 'es2019',
          parser: {
            syntax: 'typescript',
            decorators: true
          },
          transform: {
            legacyDecorator: true,
            decoratorMetadata: true
          }
        }
      })
    });
  }

  return plugins;
}

@axe-me https://vitejs.dev/guide/api-plugin.html#vite-specific-hooks