WangShuXian6 / blog

FE-BLOG
https://wangshuxian6.github.io/blog/
MIT License
45 stars 10 forks source link

esbuild #134

Open WangShuXian6 opened 2 years ago

WangShuXian6 commented 2 years ago

esbuild

https://esbuild.github.io/ An extremely fast JavaScript bundler 一个极其快速的JavaScript打包器 https://github.com/evanw/esbuild

安装

yarn add esbuild -D

建立脚本

通常需要 esbuild-node-externals 配合忽略依赖文件引用 build.tool.js


const esbuild = require("esbuild");
const { nodeExternalsPlugin } = require("esbuild-node-externals");

esbuild .build({ //logLevel: 'silent', //absWorkingDir: basePath, entryPoints: ["./src/index.ts"], outfile: "./dist/index.js", bundle: true, minify: true, //process.env.NODE_ENV === "production" platform: "browser", //"node", "browser" sourcemap: true, //process.env.NODE_ENV !== "production" target: "es6", plugins: [nodeExternalsPlugin()], }) .catch(() => process.exit(1));



## 注意
>esbuild 在生成esm时,包内如果包含cjs包时,会导致cjs内的模块无法识别  例如 `Cannot find module 'react'`
>https://stackoverflow.com/questions/68423950/when-using-esbuild-with-external-react-i-get-dynamic-require-of-react-is-not-s
WangShuXian6 commented 2 years ago

esbuild for react ui library with scss and css module

用于构建 React UI 库 【使用 css module 和 scss】 scripts/build.react.ui.js

// @ts-nocheck
const esbuild = require("esbuild");
const { nodeExternalsPlugin } = require("esbuild-node-externals");
// 自动排除捆绑版本中的所有node_modules
const svgrPlugin = require("esbuild-plugin-svgr"); //import Icon from './icon.svg';
const { sassPlugin, postcssModules } = require("esbuild-sass-plugin"); //sassPlugin({type: "lit-css"})

const iiefTask = () => {
  esbuild
    .build({
      //logLevel: 'silent',
      //absWorkingDir: basePath,
      entryPoints: ["./src/index.tsx"],
      entryNames: "[name]",
      outdir: "./dist/",
      bundle: true,
      minify: true, //process.env.NODE_ENV === "production"
      platform: "browser", //"node", "browser"
      sourcemap: true, //process.env.NODE_ENV !== "production"
      external: ["react", "react-dom"],
      target: "es6",
      loader: {
        ".svg": "dataurl",
        ".png": "dataurl",
        ".jpg": "file",
        ".jpeg": "file",
        //".svg": "file",
        ".gif": "file",
      },
      plugins: [
        nodeExternalsPlugin(),
        svgrPlugin(),
        sassPlugin({
          transform: postcssModules({
            localsConvention: "camelCaseOnly",
          }),
        }),
      ],
      inject: ["../../scripts/react-shim.js"],
    })
    .catch(() => process.exit(1));
};

const esmTask = () => {
  esbuild
    .build({
      //logLevel: 'silent',
      //absWorkingDir: basePath,
      entryPoints: ["./src/index.tsx"],
      entryNames: "[name].esm",
      format: "esm",
      //outfile: "./dist/index.esm.js",
      outdir: "./dist/", // outdir 与 outfile 互斥, outdir 与 entryNames 成对出现,互补
      bundle: true,
      minify: true,
      //platform: "browser", //"node", "browser"
      sourcemap: true,
      external: ["react", "react-dom"],
      target: "esnext",
      loader: {
        ".svg": "dataurl",
        ".png": "dataurl",
        ".jpg": "file",
        ".jpeg": "file",
        //".svg": "file",
        ".gif": "file",
      },
      plugins: [
        nodeExternalsPlugin(),
        svgrPlugin(),
        sassPlugin({
          transform: postcssModules({
            localsConvention: "camelCaseOnly",
          }),
        }),
      ],
      inject: ["../../scripts/react-shim.js"],
    })
    .catch(() => process.exit(1));
};

iiefTask();
esmTask();

为每个编译后的库文件自动注入 React 变量

scripts/react-shim.js

import * as React from  'react' 
export { React }
WangShuXian6 commented 2 years ago

esbuild for browser tool library

scripts/build.tool.js

// @ts-nocheck
//@ts-nocheck
const { realpathSync, readFileSync, writeFileSync, renameSync } = require("fs");
const esbuild = require("esbuild");
//const { basename } = require("path");
const path = require("path");

const { spawnSync } = require("child_process");

const { nodeExternalsPlugin } = require("esbuild-node-externals");
// 自动排除捆绑版本中的所有node_modules
const { Generator } = require("npm-dts");

// new Generator({
//   entry: "src/index.ts",
//   output: "dist/index.d.ts",
// }).generate();

// new Generator({
//   entry: path.resolve(process.cwd(), '"src/index.ts'),
//   root: path.resolve(process.cwd(), 'src'),
//   tmp: path.resolve(process.cwd(), 'cache/tmp'),
//   tsc: '--extendedDiagnostics',
// }).generate()

//@ts-ignore
//const  basePath: `${__dirname}/..`,

const iiefTask = () => {
  esbuild
    .build({
      //logLevel: 'silent',
      //absWorkingDir: basePath,
      entryPoints: ["./src/index.ts"],
      outfile: "./dist/index.js",
      bundle: true,
      minify: true, //process.env.NODE_ENV === "production"
      platform: "browser", //"node", "browser"
      sourcemap: true, //process.env.NODE_ENV !== "production"
      target: "es6",
      plugins: [nodeExternalsPlugin()],
    })
    .catch(() => process.exit(1));
};

const esmTask = () => {
  esbuild
    .build({
      //logLevel: 'silent',
      //absWorkingDir: basePath,
      entryPoints: ["./src/index.ts"],
      format: "esm",
      outfile: "./dist/index.esm.js",
      bundle: true,
      minify: true,
      //platform: "browser", //"node", "browser"
      sourcemap: true,
      target: "esnext",
      plugins: [nodeExternalsPlugin()],
    })
    .catch(() => process.exit(1));
};

const cjsTask = () => {
  esbuild
    .build({
      //logLevel: 'silent',
      //absWorkingDir: basePath,
      entryPoints: ["./src/index.ts"],
      outfile: "./dist/index.cjs.js",
      bundle: true,
      minify: true,
      platform: "node", //"node", "browser"
      sourcemap: true,
      format: "cjs",
      target: ["esnext", "node12.22.0"],
      plugins: [nodeExternalsPlugin()],
    })
    .catch(() => process.exit(1));
};

iiefTask();
esmTask();
cjsTask();
WangShuXian6 commented 2 years ago

esbuild for node tool library

scripts/build.node.js

// @ts-nocheck
//@ts-nocheck
const { realpathSync, readFileSync, writeFileSync, renameSync } = require("fs");
const esbuild = require("esbuild");
//const { basename } = require("path");
const path = require("path");

const { spawnSync } = require("child_process");

const { nodeExternalsPlugin } = require("esbuild-node-externals");
// 自动排除捆绑版本中的所有node_modules
const { Generator } = require("npm-dts");

// new Generator({
//   entry: "src/index.ts",
//   output: "dist/index.d.ts",
// }).generate();

// new Generator({
//   entry: path.resolve(process.cwd(), '"src/index.ts'),
//   root: path.resolve(process.cwd(), 'src'),
//   tmp: path.resolve(process.cwd(), 'cache/tmp'),
//   tsc: '--extendedDiagnostics',
// }).generate()

//@ts-ignore
//const  basePath: `${__dirname}/..`,

const iiefTask = () => {
  esbuild
    .build({
      //logLevel: 'silent',
      //absWorkingDir: basePath,
      entryPoints: ["./src/index.ts"],
      outfile: "./dist/index.js",
      bundle: true,
      minify: true, //process.env.NODE_ENV === "production"
      platform: "browser", //"node", "browser"
      sourcemap: true, //process.env.NODE_ENV !== "production"
      target: "es6",
      plugins: [nodeExternalsPlugin()],
    })
    .catch(() => process.exit(1));
};

const esmTask = () => {
  esbuild
    .build({
      //logLevel: 'silent',
      //absWorkingDir: basePath,
      entryPoints: ["./src/index.ts"],
      format: "esm",
      outfile: "./dist/index.esm.js",
      bundle: true,
      minify: true,
      //platform: "browser", //"node", "browser"
      sourcemap: true,
      target: "esnext",
      plugins: [nodeExternalsPlugin()],
    })
    .catch(() => process.exit(1));
};

const cjsTask = () => {
  esbuild
    .build({
      //logLevel: 'silent',
      //absWorkingDir: basePath,
      entryPoints: ["./src/index.ts"],
      outfile: "./dist/index.cjs.js",
      bundle: true,
      minify: true,
      platform: "node", //"node", "browser"
      sourcemap: true,
      format: "cjs",
      target: ["esnext", "node12.22.0"],
      plugins: [nodeExternalsPlugin()],
    })
    .catch(() => process.exit(1));
};

//iiefTask();
esmTask();
cjsTask();
WangShuXian6 commented 2 years ago

esbuild monorepo starter

https://github.com/WangShuXian6/esbuild-monorepo

WangShuXian6 commented 2 years ago

esbuild API

Target

这将为生成的 JavaScript 和/或 CSS 代码设置目标环境。例如,您可以将 esbuild 配置为不生成 Chrome 版本 58 无法处理的任何较新的 JavaScript 或 CSS。目标既可以设置为 JavaScript 语言版本,也可以设置为es2020单个引擎的版本列表(当前为chrome、firefox、safari、edge或node)。默认目标是esnext这意味着默认情况下,esbuild 将假定支持所有最新的 JavaScript 和 CSS 功能。

这是一个使用 esbuild 中所有可用目标环境名称的示例。请注意,您不需要指定所有这些;您可以只指定项目关心的目标环境的子集。如果您愿意,您还可以更精确地了解版本号(例如node12.19.0,而不是仅仅node12):

require('esbuild').buildSync({
  entryPoints: ['app.js'],
  target: [
    'es2020',
    'chrome58',
    'firefox57',
    'safari11',
    'edge16',
    'node12',
  ],
  outfile: 'out.js',
})

您可以参考JavaScript 加载器以了解有关在哪些语言版本中引入了哪些语法功能的详细信息。请记住,虽然 JavaScript 语言版本es2020是按年份标识的,但也就是规范被批准的年份。它与所有主要浏览器实现该规范的年份无关,该规范通常发生在该年之前或之后。

请注意,如果您使用 esbuild 尚不支持转换为当前语言目标的语法功能,则 esbuild 将在使用不受支持的语法时生成错误。例如,在针对es5语言版本时通常会出现这种情况,因为 esbuild 仅支持将大多数较新的 JavaScript 语法功能转换为es6.