跳到主要内容

手动打包

2023年03月04日
柏拉文
越努力,越幸运

Rollup 提供了可在 Node.js 中使用的 JavaScript API。一般情况下不需要使用它,而应使用命令行 API,除非你要扩展 Rollup 本身或者使用它进行一些高级操作,比如通过编程生成 bundle 下面为大家展示如何以编程的方式生成bundle

构建


src/index.ts

import "./index.scss";
import $ from "jquery";
import { getName } from "util/index";
import { getName1 } from "util/index1";
import cloneDeep from "lodash/cloneDeep";
import underscore from "underscore";

const test = () => {
return process.env.NODE_ENV;
};

const envStr = test();
console.log(envStr);

const nameStr = getName();
console.log(nameStr);
const nameStr1 = getName1();
console.log(nameStr1);

const promiseFunc = () => {
return new Promise((resolve, reject) => {
resolve(100);
});
};

const asyncFunc = async () => {
const result = await promiseFunc();
console.log(result);
};

asyncFunc();

const data = {
name: "dataName",
};

const dataCopy = cloneDeep(data);
dataCopy.name = "dataCopyName";

console.log(data);
console.log(dataCopy);

const dataCopy1 = underscore.clone(data);
dataCopy1.name = "dataCopy1Name";
console.log(data);
console.log(dataCopy1);

console.log($(".box"));

package.json

{
"name": "auto",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"build": "node scripts/build.js"
},
"devDependencies": {
"@babel/core": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.21.0",
"@rollup/plugin-alias": "^4.0.3",
"@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-commonjs": "^24.0.1",
"@rollup/plugin-html": "^1.0.2",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-typescript": "^11.0.0",
"@types/node": "^18.14.6",
"babel-plugin-lodash": "^3.3.4",
"node-sass": "^8.0.0",
"postcss": "^8.4.21",
"rollup": "^3.18.0",
"rollup-plugin-livereload": "^2.0.5",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-serve": "^2.0.2",
"sass": "^1.58.3",
"tslib": "^2.5.0",
"typescript": "^4.9.5"
},
"dependencies": {
"@types/jquery": "^3.5.16",
"@types/lodash": "^4.14.191",
"@types/underscore": "^1.11.4",
"jquery": "^3.6.3",
"lodash": "^4.17.21",
"underscore": "^1.13.6"
}
}

tsconfig.json

{
"compilerOptions": {
"baseUrl": ".",
"outDir": "dist",
"strict": true,
"newLine": "LF",
"allowJs": true,
"types": ["node"],
"jsx": "preserve",
"target": "es2015",
"module": "ESNext",
"skipLibCheck": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"moduleResolution": "node",
"lib": ["es2015", "esnext", "dom"],
"forceConsistentCasingInFileNames": true,
"paths": {
"util/*": ["src/util/*"],
}
},
"include": ["src/*"],
"exclude": ["node_modules", "dist"],
}

babel.config.js

const presets = [
[
"@babel/preset-env",
{
modules: false,
},
],
"@babel/preset-typescript",
];
const plugins = [["lodash"]];

module.exports = {
presets,
plugins,
};

scripts/build.js

const rollup = require("rollup");

const rollupOptions = require("./config");
const inputOptions = { ...rollupOptions };
const outputOptions = { ...rollupOptions.output };
const watchOptions = {
...inputOptions,
output: [outputOptions],
};

async function build() {
const bundle = await rollup.rollup(inputOptions);
await bundle.write(outputOptions);
rollup.watch(watchOptions);
}

build();

scripts/config.js

const path = require("path");
const RollupPluginHtml = require("@rollup/plugin-html");
const RollupPluginJson = require("@rollup/plugin-json");
const RollupPluginServe = require("rollup-plugin-serve");
const RollupPluginAlias = require("@rollup/plugin-alias");
const RollupPluginBabel = require("@rollup/plugin-babel");
const RollupPluginTerser = require("@rollup/plugin-terser");
const RollupPluginPostcss = require("rollup-plugin-postcss");
const RollupPluginReplace = require("@rollup/plugin-replace");
const RollupPluginCommonjs = require("@rollup/plugin-commonjs");
const RollupPluginLiverLoad = require("rollup-plugin-livereload");
const RollupPluginTypescript = require("@rollup/plugin-typescript");
const RollupPluginNodeResolve = require("@rollup/plugin-node-resolve");

const resolve = (p) => {
return path.resolve(__dirname, "../", p);
};
const version = require("../package.json").version;
const extensions = {
babel: [".ts", ".js"],
common: [".ts", ".tsx", ".js", ".jsx", ".json", ".css", ".sass", ".scss"],
};
const customResolver = RollupPluginNodeResolve({
extensions: extensions.common,
});
const customHtmlTemplate = async ({
attributes,
files,
meta,
publicPath,
title,
}) => {
const scripts = (files.js || [])
.map(({ fileName }) => {
const attrs = RollupPluginHtml.makeHtmlAttributes(attributes.script);
return `<script src="${publicPath}${fileName}"${attrs}></script>`;
})
.join("\n");

const links = (files.css || [])
.map(({ fileName }) => {
const attrs = RollupPluginHtml.makeHtmlAttributes(attributes.link);
return `<link href="${publicPath}${fileName}" rel="stylesheet"${attrs}>`;
})
.join("\n");

const metas = meta
.map((input) => {
const attrs = RollupPluginHtml.makeHtmlAttributes(input);
return `<meta${attrs}>`;
})
.join("\n");

return `
<!doctype html>
<html${RollupPluginHtml.makeHtmlAttributes(attributes.html)}>
<head>
${metas}
<title>${title}</title>
${links}
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/underscore.js/1.13.6/underscore-umd.min.js"></script>
</head>
<body>
${scripts}
</body>
</html>`;
};

const rollupPlugins = [
RollupPluginJson(),
RollupPluginAlias({
entries: [
{ find: "util", replacement: resolve("src/util") },
],
customResolver,
}),
RollupPluginBabel.babel({
babelHelpers: "bundled",
exclude: ["node_modules/**"],
extensions: extensions.babel,
}),
RollupPluginCommonjs(),
RollupPluginNodeResolve.nodeResolve({
extensions: extensions.common,
}),
RollupPluginTypescript({
tsconfig: resolve("tsconfig.json"),
cacheDir: ".rollup.tscache",
}),
RollupPluginReplace({
___VERSION__: version,
preventAssignment: true,
__DEV__: process.env.NODE_ENV === "development",
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
}),
RollupPluginTerser({
maxWorkers: 4,
}),
RollupPluginServe({
open: true,
port: 4000,
contentBase: ["dist"],
}),
RollupPluginLiverLoad({
watch: "dist",
}),
RollupPluginPostcss(),
RollupPluginHtml({
fileName: "index.html",
title: "Rollup 通用开发环境",
template: customHtmlTemplate,
}),
];

module.exports = {
cache: true,
watch: {
include: "src/**",
exclude: "node_modules/**"
},
input: resolve("src/index.ts"),
output: {
file: path.resolve("dist/index.js"),
format: "umd",
banner: `/** Rollup 通用开发环境 版本 v${version} **/`,
name: "RollupName",
exports: "auto",
globals: {
jquery: "$",
underscore: "_",
},
},
plugins: rollupPlugins,
external: ["jquery", "underscore"],
};

命令行


  1. 初始化项目: 通过yarn init -y 初始化项目

  2. 配置命令行: 通过package.json - scripts 配置命令行

  3. 配置rollup命令行

"scripts": {
"build": "rollup --watch --config rollup.config.js --environment NODE_ENV:development"
}

替换变量


Rollup 通过 @rollup/plugin-replace 构建产物时替换变量

相关代码

const RollupPluginReplace = require("@rollup/plugin-replace");

RollupPluginReplace({
___VERSION__: version,
preventAssignment: true,
__DEV__: process.env.NODE_ENV === "development",
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
})

压缩产物


通过@rollup/plugin-terser压缩构建产物

相关代码

const RollupPluginTerser = require("@rollup/plugin-terser");

RollupPluginTerser({
maxWorkers: 4,
})

支持 Css


通过rollup-plugin-postcss来支持引入.css.scss.less等样式文件

相关代码

const RollupPluginPostcss = require("rollup-plugin-postcss");

RollupPluginPostcss()

支持 CDN


  1. 通过external将模块保留在bundle外部(忽略打包)

    external: ["jquery", "underscore"]
  2. 通过output.globals注册外部依赖的全局变量: 外部依赖 : 全局变量 中, 外部依赖是所引入的依赖包名, 全局变量是该依赖的CDN文件挂载在window上的属性名。

    external: ["jquery", "underscore"],

    output: {
    globals: {
    jquery: "$",
    underscore: "_",
    }
    }
  3. 通过output.format指定生成的bundle格式: 如果需要在html等浏览器用到外部的依赖,需要使用umd或者iife的格式

    output: {
    format: "iife",
    }
  4. index.html模版中引入外部依赖的CDN地址

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/underscore.js/1.13.6/underscore-umd.min.js"></script>

支持 Alias


Rollup 通过@rollup/plugin-alias@rollup/plugin-node-resolve来支持路径别名

const RollupPluginAlias = require("@rollup/plugin-alias");
const RollupPluginNodeResolve = require("@rollup/plugin-node-resolve");

const customResolver = RollupPluginNodeResolve({
extensions: extensions.common,
});

RollupPluginAlias({
entries: [
{ find: "util", replacement: path.resolve(__dirname, "src", "util") },
],
customResolver,
})

支持 HTML


Rollup 通过@rollup/plugin-html来自动生成HTML模版

相关代码

const RollupPluginHtml = require("@rollup/plugin-html");

const customHtmlTemplate = async ({
attributes,
files,
meta,
publicPath,
title
}) => {
const scripts = (files.js || [])
.map(({ fileName }) => {
const attrs = RollupPluginHtml.makeHtmlAttributes(attributes.script);
return `<script src="${publicPath}${fileName}"${attrs}></script>`;
})
.join('\n');

const links = (files.css || [])
.map(({ fileName }) => {
const attrs = RollupPluginHtml.makeHtmlAttributes(attributes.link);
return `<link href="${publicPath}${fileName}" rel="stylesheet"${attrs}>`;
})
.join('\n');

const metas = meta
.map((input) => {
const attrs = RollupPluginHtml.makeHtmlAttributes(input);
return `<meta${attrs}>`;
})
.join('\n');

return `
<!doctype html>
<html${ RollupPluginHtml.makeHtmlAttributes(attributes.html)}>
<head>
${metas}
<title>${title}</title>
${links}
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/underscore.js/1.13.6/underscore-umd.min.js"></script>
</head>
<body>
${scripts}
</body>
</html>`;
};


RollupPluginHtml({
fileName: "index.html",
title: "Rollup 通用开发环境",
template: customHtmlTemplate
})

支持 Babel


为了能够使用浏览器和 Node.js 尚不支持的最新 JavaScript 特性,许多开发人员会在项目中使用 Babel。需要安装以下依赖:

  • @babel/core

  • @babel/preset-env

  • babel-plugin-lodash

  • @rollup/plugin-babel

  • @babel/preset-typescript

  1. 安装相关依赖

    yarn add @babel/core @babel/preset-env babel-plugin-lodash @rollup/plugin-babel @babel/preset-typescript -D
  2. 配置babel

    const presets = [
    [
    "@babel/preset-env",
    {
    modules: false,
    },
    ],
    "@babel/preset-typescript",
    ];
    const plugins = [["lodash"]];

    module.exports = {
    presets,
    plugins,
    };

  3. 配置rollup.plugins

    const RollupPluginBabel = require("@rollup/plugin-babel");

    RollupPluginBabel.babel({
    babelHelpers: "bundled",
    exclude: ["node_modules/**"],
    extensions: extensions.babel,
    })

支持 Server


通过rollup-plugin-serve开启本地化服务

相关代码

const RollupPluginServe = require("rollup-plugin-serve");

RollupPluginServe({
open: true,
port: 4000,
contentBase: ["dist"],
})

支持 TypeScript


为了能够使用浏览器和 Node.js 使用TypeScript特性,需要安装以下依赖:

  • tslib

  • typescript

  • @types/node

  • @rollup/plugin-typescript

  1. Typescript初始化: 根目录执行tsc --init, 生成 tsconfig.json

  2. TypeScript相关配置: 配置如下

    {
    "compilerOptions": {
    "baseUrl": ".",
    "outDir": "dist",
    "strict": true,
    "newLine": "LF",
    "allowJs": true,
    "types": ["node"],
    "jsx": "preserve",
    "target": "es2015",
    "module": "ESNext",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "moduleResolution": "node",
    "lib": ["es2015", "esnext", "dom"],
    "forceConsistentCasingInFileNames": true,
    "paths": {
    "util/*": ["src/util/*"],
    }
    },
    "include": ["src/*"],
    "exclude": ["node_modules", "dist"],
    }
    • compilerOptions.baseUrl: 项目基础路径

    • compilerOptions.outDir:

    • compilerOptions.paths: 用于配置路径别名, 该配置项需要指定baseUrl

  3. rollup配置Typescript插件

    const RollupPluginTypescript = require("@rollup/plugin-typescript");

    RollupPluginTypescript({
    tsconfig: path.resolve(__dirname, "tsconfig.json"),
    cacheDir: ".rollup.tscache",
    })

支持 Livereload


rollup 通过 rollup-plugin-livereload 来支持本地开发环境的热更新

相关代码

const RollupPluginLiverLoad = require("rollup-plugin-livereload");

RollupPluginLiverLoad({
watch: 'dist',
})

支持 Json Import


rollup 通过 @rollup/plugin-json 来支JSON文件的引入

相关代码

const RollupPluginJson = require("@rollup/plugin-json");

RollupPluginJson()

支持 EsModule Import


rollup 通过 @rollup/plugin-node-resolve 来支EsModule引入方式

相关代码

const RollupPluginNodeResolve = require("@rollup/plugin-node-resolve");

RollupPluginNodeResolve.nodeResolve({
extensions: extensions.common,
})

支持 CommonJs Import


rollup 通过 @rollup/plugin-commonjs 来支CommonJs引入方式

相关代码

const RollupPluginCommonjs = require("@rollup/plugin-commonjs");

RollupPluginCommonjs()