Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vite实战小结 #23

Open
laoyutong opened this issue Feb 28, 2022 · 0 comments
Open

Vite实战小结 #23

laoyutong opened this issue Feb 28, 2022 · 0 comments

Comments

@laoyutong
Copy link
Owner

区分开发和生产环境

在打包的时候,将产物的静态资源路径替换成cdn路径前缀
通过process.env.NODE_ENV是否是production来判断,开发的时候环境变量可能为空,导致开发路径不符合预期

{
    base: process.env.NODE_ENV === "production" ? CDN_URL_PREFIX : "/",
}

cdn插件

不打包react这些第三方库,直接通过相应的cdn链接来引入
解析需要处理的模块配置,读取其在node_modules里的版本,通过rollup-plugin-external-globals插件来转换打包代码,然后通过vite提供的transform钩子插入script标签来引入cdn资源

import {
  UserConfig,
  PluginOption,
} from "vite";
import externalGlobals from "rollup-plugin-external-globals";

const prodUrl = "https://xxxxxx/:name@:version/:path";

const modules: vitePluginCDNOption["modules"] = [
  {
    name: "react",
    var: "React",
  },
  {
    name: "react-dom",
    var: "ReactDOM",
  },
  {
    name: "history",
    var: "HistoryLibrary",
  },
  {
    name: "react-router",
    var: "ReactRouter",
  },
  {
    name: "react-router-dom",
    var: "ReactRouterDOM",
  },
];

const getVersionInNodeModules = (name, pathToNodeModules = process.cwd()) => {
  const packageJson = "package.json";
  try {
    return require(path.join(
      pathToNodeModules,
      "node_modules",
      name,
      packageJson
    )).version;
  } catch (e) {
    return null;
  }
};

const vitePluginCDN: (option: vitePluginCDNOption) => PluginOption = (
  option: vitePluginCDNOption
) => {
  const { modules, prodUrl } = option;
  return {
    name: "vite-plugin-cdn",
    enforce: "post",
    transformIndexHtml: {
      config: () => {
        const userConfig: UserConfig = {
          build: {
            rollupOptions: {},
          },
        };
        const externalMap = {};
        modules.forEach((module) => {
          externalMap[module.name] = module.var;
        });
        userConfig.build.rollupOptions = {
          plugins: [externalGlobals(externalMap)],
        };
        return userConfig;
      },
      transform: async (html) => {
        return {
          html,
          tags: modules.map(({ name, path }) => {
            const version = getVersionInNodeModules(name);
            return {
              tag: "script",
              attrs: {
                defer: "defer",
                src: prodUrl
                  .replace(":name", name)
                  .replace(":version", version ?? "latest")
                  .replace(":path", path ?? `umd/${name}.production.min.js`),
              },
            };
          }),
        };
      },
    },
  };
};

第三方库解析问题

如果一个esm的包里使用了require来导入css文件,就会有如下报错:Uncaught Error: Dynamic require of "xxx/main.scss" is not supported, when ESM package import commonjs module
vite里也有相应的issue,可以通过插件@originjs/vite-plugin-commonjs来解决

import { viteCommonjs } from '@originjs/vite-plugin-commonjs'
export default {
    plugins: [
        viteCommonjs()
    ]
}

如果引入一个第三方库遇到一堆莫名其妙的报错,可能是该库的打包方式有些问题,可以通过esbuildCommonjs处理该第三方库的依赖来解决

import { resolvePackageData } from "vite";
import { esbuildCommonjs } from "@originjs/vite-plugin-commonjs";

// 获取有问题的第三方库依赖
const deps = resolvePackageData("wrong-pkg", __dirname).data
  .dependencies;

export default defineConfig({
  optimizeDeps: {
    esbuildOptions: {
      plugins: [esbuildCommonjs([...Object.keys(deps)])],
    },
  },
});

通过optimizeDeps.include拆包

默认情况下,不在 node_modules 中的,链接的包不会被预构建。使用该配置项可强制预构建链接的包
如果填写第三方库的依赖,可以进行拆包处理

const deps = resolvePackageData("xxxxx", __dirname).data
  .dependencies;

const optimizeDeps = Object.keys(deps).map(
  (item) => `xxxxx > ${item}`
);

{
  optimizeDeps: {
    include: [...optimizeDeps],
  },
}

原本在node_modules.vite下只会有一个xxxxx,在拆包之后就会是xxxxx_dep1xxxxx_dep2的形式

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant