美文网首页
初识rollup 打包、配置vue脚手架

初识rollup 打包、配置vue脚手架

作者: z_hboot | 来源:发表于2023-03-08 22:35 被阅读0次

    rollup javascript 代码打包器,它使用了 es6 新标准代码模块格式。

    特点:

    1. 面向未来,拥抱 es 新标准,支持标准化模块导入、导出等新语法。
    2. tree shaking 静态分析导入的代码。排除未实际引用的内容
    3. 兼容现有的 commonJS 模块,可通过插件导入

    示例项目地址

    安装使用

    创建示例项目

    $> mkdir rollup-example
    $> cd rollup-example
    

    安装 rollup

    $> npm init -y
    $> npm i rollup
    

    创建main.js 主入口文件。创建 libs目录用于方式封装的功能函数。

    package.json文件中定义执行脚本命令。

    • --file 编译后的文件名称 简写 -o
    • --format 按什么标准去编译文件类型 iffe、cjs、es。 简写-f
    {
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "rollup main.js --file bundle.js --format iife"
      }
    }
    

    libs创建arry.js

    /**
     * 数组类型校验
     * @param {*} target
     * @returns
     */
    export const isArray = (target) => {
      return Array.isArray(target);
    };
    /**
     * 数组去重
     * @param {*} target
     * @returns
     */
    export const duplicateKill = (target) => {
      return [...new Set(target)];
    };
    

    然后在main.js 中调用

    import { isArray } from "./libs/array";
    
    //
    console.log(isArray(3));
    console.log(isArray("1,2,3,4"));
    console.log(isArray([1, 2, 3, 4]));
    

    执行npm run build,得到一个编译文件bundle.js

    (function () {
      "use strict";
    
      /**
       * 数组类型校验
       * @param {*} target
       * @returns
       */
      const isArray = (target) => {
        return Array.isArray(target);
      };
    
      //
      console.log(isArray(3));
      console.log(isArray("1,2,3,4"));
      console.log(isArray([1, 2, 3, 4]));
    })();
    

    通过配置文件定义编译配置

    上面使用了rollup 命令,并通过命令行参数指定文件以及编译类型。

    定义rollup.config.js 文件,定义编译输出

    // rollup.config.js
    
    export default {
      input: "main.js",
      output: {
        file: "dist/bundle.js",
        format: "iife",
      },
    };
    

    然后修改package.json

    • --config 指定配置文件, 简写-c
    • --bundleConfigAsCjs 因为配置文件是以 .js结尾的,通常建议使用.cjs.
    {
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "rollup --config rollup.config.js --bundleConfigAsCjs"
      }
    }
    

    然后执行 npm run build 可以看到 生成的dis/bundle.js

    也可以省略 配置文件,rollup 会自动加载根目录下的rollup.config.js , rollup --config --bundleConfigAsCjs

    多入口打包文件,配置文件可以是数组对象

    会有一些多入口页面打包,通过配置入口,删除不同目录文件的编译资源

    定义rollup.config.js 文件

    // rollup.config.js
    
    export default [
        {
            input: "main.js",
            output: {
                file: "dist/bundle.js",
                format: "iife",
            }
        },
        {
            input: "login.js",
            output: {
                file: "dist/login.js",
                format: "iife",
            }
        }
    ],
    

    如果想要输出多个类型的编译资源output 配置为数组

    // rollup.config.js
    
    export default [
        {
            input: "main.js",
            output: [
                {
                    file: "dist/bundle.js",
                    format: "iife",
                },
                {
                    file: "dist/bundle-es.js",
                    format: "es",
                },
                {
                    file: "dist/bundle-cjs.js",
                    format: "cjs",
                }
            ]
        },
    ],
    

    可异步请求配置文件

    如果是在线配置,存储在后端。可通过请求获取配置文件。

    // rollup.config.js
    import ajax from "libs/ajax";
    export default ajax.get("/**/**/rolleup-config");
    

    多接口、都入口配置,则改为

    // rollup.config.js
    import ajax from "libs/ajax";
    export default Promise.all([
      ajax.get("/**/**/rolleup-config-main"),
      ajax.get("/**/**/rolleup-config-login"),
    ]);
    

    通过命令行参数适用不同的配置文件

    开发坏境和生产环境有不同的配置。通过命令行参数,使用对应的配置文件。

    // rollup.config.js
    import devConfig from "./build/rollup.dev.config.js";
    import prdConfig from "./build/rollup.prd.config.js";
    
    export default (commandLineArgs) => {
      if (commandLineArgs.environment === "dev") {
        return devConfig;
      }
      return prdConfig;
    };
    

    修改package.json 提供 dev、build 脚本

    {
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "rollup --config --environment dev --bundleConfigAsCjs",
        "build": "rollup --config --bundleConfigAsCjs --environment prd"
      }
    }
    

    rollup.config.js 配置文件说明

    // rollup.config.js
    
    // can be an array (for multiple inputs)
    export default {
      // core input options
      external,
      input: "main.js", // 主入口文件配置路径
      plugins, // 使用插件,
    
      // advanced input options
      cache,
      onwarn,
      preserveEntrySignatures,
      strictDeprecations,
    
      // danger zone
      acorn,
      acornInjectPlugins,
      context,
      moduleContext,
      preserveSymlinks,
      shimMissingExports,
      treeshake,
    
      // experimental
      experimentalCacheExpiry,
      perf,
    
      // required (can be an array, for multiple outputs)
      output: {
        // core output options
        dir: "dist", // 编译文件目录地址,多个编译文件则必须指定
        file: "dist/bundle.js", // 编译后文件目录路径
        format, // 文件编译类型 es cjs iife
        globals,
        name,
        plugins, // 针对某些输出的插件
    
        // advanced output options
        assetFileNames,
        banner,
        chunkFileNames,
        compact,
        entryFileNames,
        extend,
        footer,
        hoistTransitiveImports,
        inlineDynamicImports,
        interop,
        intro,
        manualChunks,
        minifyInternalExports,
        outro,
        paths,
        preserveModules,
        preserveModulesRoot,
        sourcemap,
        sourcemapBaseUrl,
        sourcemapExcludeSources,
        sourcemapFile,
        sourcemapPathTransform,
        validate,
    
        // danger zone
        amd,
        esModule,
        exports,
        externalLiveBindings,
        freeze,
        indent,
        namespaceToStringTag,
        noConflict,
        preferConst,
        sanitizeFileName,
        strict,
        systemNullSetters,
      },
    
      watch: {
        buildDelay,
        chokidar,
        clearScreen,
        skipWrite,
        exclude,
        include,
      },
    };
    

    使用一个加载json文件的插件

    安装

    $> npm i --save-dev @rollup/plugin-json
    

    在配置中使用插件

    // rollup.config.js prd
    import PluginJson from "@rollup/plugin-json";
    
    export default {
      input: "main.js",
      output: {
        file: "dist/bundle.js",
        format: "iife",
      },
      plugins: [PluginJson()],
    };
    

    然后在项目中可以导入 JSON 文件,按对象取值。

    import { version } from "./package.json";
    // import packageJson from "./package.json";
    
    console.log(version);
    

    可以针对输出output 配置插件

    最小化构建代码,压缩代码,安装@rollup/plugin-terser

    $> npm install --save-dev @rollup/plugin-terser
    

    修改配置文件,在编译类型为 es 的输出使用插件

    // rollup.config.js dev
    import PluginJson from "@rollup/plugin-json";
    import PluginTerser from "@rollup/plugin-terser";
    
    export default {
      input: "main.js",
      output: [
        {
          file: "dist/bundle.js",
          format: "iife",
        },
        {
          file: "dist/bundle-es.js",
          format: "es",
          plugins: [PluginTerser()],
        },
        {
          file: "dist/bundle-cjs.js",
          format: "cjs",
        },
      ],
      plugins: [PluginJson()],
    };
    

    执行npm run build 可以看到bundle-es.js文件代码被压缩,没有任何格式

    动态加载已使用代码拆分

    在以下情况会自动进行代码拆分

    • 动态加载模块
    • 多入口引入统一模块。
    • 通过输出配置output.manualChunks指定需要拆分的模块

    [!] RollupError: Invalid value "iife" for option "output.format" - UMD and IIFE output formats are not supported for code-splitting builds.

    编译类型 UMD、IIFE 是不支持代码拆分的。改用 cjs

    实现login模块的拆分,创建 login 文件入口。然后在 main.js 文件中动态引入

    import("./login.js").then(() => console.log("成功加载login..."));
    

    需要修改配置指定编译目录dir:'dist',原来指定的 file 只是编译生成一个文件包。现在拆分代码,会生成多个编译包。

    // rollup.config.js prd
    import PluginJson from "@rollup/plugin-json";
    
    export default {
      input: "main.js",
      output: {
        // file: "dist/bundle.js",
        format: "cjs",
        dir: "dist",
      },
      plugins: [PluginJson()],
    };
    
    build-dir.png

    定义插件,以满足定制化需求

    编译时可能会需要一些定制化处理。通过自定义插件实现代码的转换。

    示例实现一个移除console.log 的代码。一个插件约束

    • 插件名需要以rollup-plugin-**开头
    • package.json 中包含 rollup-plugin 关键字,构建后发布之前需要加前缀
    • 经过全面的测试。
    • 插件中尽可能的使用英文说明。
    • 尽可能的使用异步方法读取文件,比如使用 fs.readFile 而不是 fs.readFileSync
    • 插件是虚拟模块时,前缀追加\0.以便其他插件不去处理它。

    项目目录下创建存储插件的位置 plugins/rollup-plugin-clear-console.js

    // rollup-plugin-clear-console
    import { createFilter } from "@rollup/pluginutils";
    
    export default function clearConsole(options = {}) {
      // filter file
      var filter = createFilter(options.include, options.exclude);
      return {
        name: "clear-console",
        transform(code, id) {
          /**
           * code 为加载的文件内容
           * id 为当前内容文件的路径地址,通过filter判断是否符合处理的要求
           */
          if (!filter(id)) return;
          try {
            return {
              code: code.replace(/console\.log(\w*)/gi, ""),
              map: { mappings: "" },
            };
          } catch (err) {
            var message = "An error occurred during processing";
            this.error({ message: message, id: id, cause: err });
            return null;
          }
        },
      };
    }
    

    @rollup/pluginutils 是针对编写 rollup 插件封装的一些功能性的函数,比如示例中使用了createFilter,可以帮助过滤指定的文件、排除指定文件。

    rollup.config.dev.js使用自定义插件,并制定处理目录下为main.js的文件。

    // rollup.config.js prd
    import PluginJson from "@rollup/plugin-json";
    // 自定义插件
    import PluginClearConsole from "../plugins/rollup-plugin-clear-console";
    
    export default {
      input: "main.js",
      output: {
        // file: "dist/bundle.js",
        format: "cjs",
        dir: "dist",
      },
      plugins: [
        PluginJson(),
        PluginClearConsole({
          include: ["**/main.js"],
        }),
      ],
    };
    

    然后执行脚本,看看效果npm run dev

    dis/main.js文件中可以看到所有的console.log都被移除。而且由于移除这些代码,一些导入的变量未被使用,也被 tree shaking 了。

    build-compare.png

    可以看到拆包编译的login.js文件中还是包含有console.log代码的。

    配置一起使用vue

    需要安装的 vue 相关的插件, 在 rollup-awesome 官方推荐的组件库

    $> npm install rollup-plugin-vue vue --save-dev
    

    安装的都是最新版本,vue 版本为3.2.45

    创建 src 目录,用于 vue 视图组件的存放位置。

    // index.js
    import { createApp } from "vue";
    
    import App from "./App.vue";
    
    const app = createApp(App);
    
    app.mount("#app");
    

    在项目目录下创建 index.html 文件

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>rollup-vue2</title>
      </head>
      <body>
        <div id="app"></div>
        <!-- 导入编译后的文件包 -->
        <script src="./dist/index.js"></script>
      </body>
    </html>
    

    修改 rollup 配置文件rollup.config.dev.js

    // rollup.config.dev.js dev
    import PluginJson from "@rollup/plugin-json";
    import PluginVue from "rollup-plugin-vue";
    // 自定义插件
    import PluginClearConsole from "../plugins/rollup-plugin-clear-console";
    
    export default {
      input: "./src/index.js",
      output: {
        // file: "dist/bundle.js",
        format: "es",
        dir: "dist",
      },
      plugins: [
        PluginVue(),
        PluginJson(),
        PluginClearConsole({
          include: ["**/main.js"],
        }),
      ],
    };
    

    然后执行 npm run dev ,打包编译后,通过live server启动一个服务访问 index.html

    服务启动页面不展示问题

    1. 页面打开后没有任何展示,控制台报错 Cannot use import statement outside a module ,查看编译包./dist/index.js . 没有将 vue 一起打包进去。加载不到

    解决,安装依赖@rollup/plugin-node-resolve ,将 vue 一起编译进去。

    $> npm install @rollup/plugin-node-resolve --save-dev
    

    修改配置,引入插件。 可以将 node_modules 中的组件包引入打包进编译包。

    // rollup.config.dev.js dev
    import PluginNodeResolve from "@rollup/plugin-node-resolve";
    
    export default {
      // ... other
      plugins: [
        // ... other
        PluginNodeResolve(),
      ],
    };
    
    1. 可以看到编译包变大了,vue 已经打包进去了,但是页面还不展示,报错Uncaught ReferenceError: process is not defined, 查看编译包./dist/index.js ,引用全局变量process.env.NODE_ENV 没有定义

    解决,安装插件 @rollup/plugin-replace

    $> npm install @rollup/plugin-replace --save-dev
    

    修改配置,引入插件。 编译后替换编译包中的目标字符串。

    // rollup.config.dev.js dev
    import PluginReplace from "@rollup/plugin-replace";
    
    export default {
      // ... other
      plugins: [
        // ... other
        PluginReplace({
          "process.env.NODE_ENV": JSON.stringify("development"),
          preventAssignment: true,
        }),
      ],
    };
    

    页面打开展示正常。

    生成 html 文件,npm run dev创建一个服务

    为了达到开发的目的,需要自动生成 html 文件,自动注入人编译后的资源包。还有其他资源的解析、加载等。

    生成 html 文件

    安装依赖插件,生成 index.html,并将所有编译的资源包添加到页面上。

    $> npm install @rollup/plugin-html --save-dev
    

    使用插件

    // rollup.config.dev.js dev
    import PluginHtml from "@rollup/plugin-html";
    
    export default {
      // ... other
      plugins: [
        // ... other
        PluginHtml({
          title: "rollup-vue3",
          fileName: "index.html",
        }),
      ],
    };
    

    开发模式,启动 serve 服务

    安装依赖插件,启动一个服务

    $> npm install rollup-plugin-serve --save-dev
    

    使用插件

    // rollup.config.dev.js dev
    import PluginServe from "rollup-plugin-serve";
    
    export default {
      // ... other
      plugins: [
        // ... other
        PluginServe({
          // 运行在浏览器中
          open: true,
          // 运行成功后,打开的地址
          openPage: "/",
          // 打印服务地址
          verbose: true,
          // 地址,端口号
          // host:"::",
          host: "127.0.0.1",
          port: 8009,
          // https 协议配置
          // https: {},
          // 运行成功,事件
          onListening: function (server) {
            const address = server.address();
            const host = address.address === "::" ? "localhost" : address.address;
            // by using a bound function, we can access options as `this`
            const protocol = this.https ? "https" : "http";
            console.log(
              `Server listening at ${protocol}://${host}:${address.port}/`
            );
          },
        }),
      ],
    };
    

    运行成功后,未自动打开浏览器,serve 配置中的 open、openPage 暂时没有发现其作用
    设置"::"不生效,设置为“127.0.0.1” 启动后正常打开。

    --watch 监听模式,开发是文件变动重新编译

    服务虽然启动了,但也仅仅是一个静态资源的服务,在开发的时候,通常需要实时编译改动的文件,希望立刻看到变化

    修改启动脚本,在监听模式下,文件发生更改,就会重新编译。--watch 等同于 -w

    {
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
      - "dev": "rollup --config --environment dev --bundleConfigAsCjs -w",
      + "dev": "rollup --config --environment dev --bundleConfigAsCjs",
      },
    }
    

    虽然重新编译了,但是浏览器中还是需要手动刷新才能看到变化。--需要唤起浏览器服务的插件--

    解析.vue中的样式 style

    在 App.vue 中书写了样式,发现在页面中没有生效

    <style>
    .app p {
      font-size: 32px;
    }
    </style>
    

    增加插件postcss \ rollup-plugin-postcss

    $> npm i postcss rollup-plugin-postcss -D
    

    配置rollup.config.dev.js

    import PluginPostCss from "rollup-plugin-postcss";
    
    export default {
      //...
      plugins: [
        //...
        PluginPostCss(),
      ],
    };
    

    重新运行,可以看到样式生效了。默认编译后的 css 样式是注入到 html 的 head 中。

    使用预编译 less

    安装 less

    $> npm i less -D
    

    即可直接使用

    <style lang="less">
    .app {
      p {
        font-size: 32px;
        color: aqua;
      }
      button {
        color: red;
      }
    }
    </style>
    

    支持 JSX 语法

    比较喜欢 jsx 语法的书写方式,实现相关配置;

    import { defineComponent } from "vue";
    
    export default defineComponent({
      name: "IFunLazySelect",
      render() {
        return (
          <div class="lazy-select">
            {/* 相关代码 */}
          </div>
    })
    

    安装 @vue/babel-plugin-jsx, 还需要安装@babel/core 、@babel/preset-env

    $> npm install @vue/babel-plugin-jsx @babel/core @babel/preset-env -D
    

    新建.babelrc.js,配置

    module.exports = {
      presets: [["@babel/env", { modules: false }]],
      plugins: ["@vue/babel-plugin-jsx"],
    };
    

    这只是 babel 配置,还需要集成到 rollup 中,使之生效,安装@rollup/plugin-babel

    则需要修改rollup.config.base.js,增加插件配置。

    // rollup.config.base.js
    
    import PluginBabel from "@rollup/plugin-babel";
    
    export default {
      plugins: [
        // ... other
        PluginBabel({ babelHelpers: "bundled" }),
      ],
    };
    

    重新启动项目,完美运行。

    其他插件

    1. 解析 commonJS 模块,转换成 es6 模块。安装依赖
    $> npm install @rollup/plugin-commonjs --save-dev
    

    修改配置

    // rollup.config.dev.js dev
    import PluginCommonJS from "@rollup/plugin-commonjs";
    
    export default {
      // ... other
      plugins: [
        // ... other
        PluginCommonJS(),
      ],
    };
    
    1. 全局注入,比如使用 jquery,安装依赖
    $> npm install @rollup/plugin-inject --save-dev
    

    修改配置

    // rollup.config.dev.js dev
    import PluginInject from "@rollup/plugin-inject";
    
    export default {
      // ... other
      plugins: [
        // ... other
        PluginInject({
          $: "jquery",
        }),
      ],
    };
    
    1. 定义别名路径,比如通常使用@代替./src路径
    $> npm install @rollup/plugin-alias --save-dev
    

    修改配置

    // rollup.config.dev.js dev
    import PluginAlias from "@rollup/plugin-alias";
    
    export default {
      // ... other
      plugins: [
        // ... other
        PluginAlias({
          entries: {
            "@": "../src",
            libs: "../libs",
          },
        }),
      ],
    };
    
    1. 加载图片资源,.png\.jpeg\.svg
    $> npm install @rollup/plugin-image --save-dev
    

    修改配置

    // rollup.config.dev.js dev
    import PluginImage from "@rollup/plugin-image";
    
    export default {
      // ... other
      plugins: [
        // ... other
        PluginImage(),
      ],
    };
    

    相关文章

      网友评论

          本文标题:初识rollup 打包、配置vue脚手架

          本文链接:https://www.haomeiwen.com/subject/bvtaldtx.html