挑战21天手写前端框架 day21 什么?一个上线的 React 项目只有 100+KB?

简介: 挑战21天手写前端框架 day21 什么?一个上线的 React 项目只有 100+KB?

image.png

开发完毕后就要编译上线了,因为编译和开发的构建部分基本上是一致的,只需要注意几个编译上线的而外差异,比如不需要开发服务,代码构建压缩,产物使用想对路径等。


增加 malita build

program.command('build').description('框架构建命令').action(function() {
    const {
        build
    } = require('../lib/build');
    build();
});
复制代码


新建 packages/malita/src/build.ts

import { build as esbuild } from 'esbuild';
import { DEFAULT_PLATFORM } from './constants';
import { style } from './styles';
import { getAppData } from './appData';
import { getUserConfig } from './config';
import { getRoutes } from './routes';
import { generateEntry } from './entry';
import { generateHtml } from './html';
export const build = async () => {
    const cwd = process.cwd();
    // 生命周期
    // 获取项目元信息 
    const appData = await getAppData({
        cwd
    });
    // 获取用户数据
    const userConfig = await getUserConfig({
        appData, isProduction: true
    });
    // 获取 routes 配置
    const routes = await getRoutes({ appData });
    // 生成项目主入口
    await generateEntry({ appData, routes, userConfig });
    // 生成 Html
    await generateHtml({ appData, userConfig, isProduction: true });
    // 执行构建
    await esbuild({
        format: 'iife',
        logLevel: 'error',
        outdir: appData.paths.absOutputPath,
        platform: DEFAULT_PLATFORM,
        bundle: true,
        minify: true,
        define: {
            'process.env.NODE_ENV': JSON.stringify('production'),
        },
        external: ['esbuild'],
        plugins: [style()],
        entryPoints: [appData.paths.absEntryPath],
    });
}
复制代码

值得注意的是我们开发的时候,需要监听文件变化重启开发服务,但是在编译的时候,我们不需要了,所以关于 rebuildwatch 相关的逻辑,我们都可以不执行。


修改 getUserConfig

getUserConfig 中我们使用 isProduction: true 来进行逻辑的区分。

await build({
    format: 'cjs',
    logLevel: 'error',
    outdir: appData.paths.absOutputPath,
    bundle: true,
    watch: isProduction ? false : {
        onRebuild: (err, res) => {
            if (err) {
                console.error(JSON.stringify(err));
                return;
            }
            malitaServe?.emit('REBUILD', { appData });
        }
    },
    define: {
        'process.env.NODE_ENV': JSON.stringify(isProduction ? 'production' : 'development'),
    },
    external: ['esbuild'],
    entryPoints: [configFile],
});
复制代码


html 生成

在开发服务的时候,我们生成 html 的时候,js 文件的引用是采用前缀匹配走静态资源服务。但是在构建的时候,我们的静态资源会被写到和 html 的相对路径下的文件夹(或者同一个文件夹)。

// <script src="/${DEFAULT_OUTDIR}/${DEFAULT_FRAMEWORK_NAME}.js"></script>
// <script src="/malita/client.js"></script>
<script src="${isProduction ? '.' : `/${DEFAULT_OUTDIR}`}/${DEFAULT_FRAMEWORK_NAME}.js"></script>
${isProduction ? '' : '<script src="/malita/client.js"></script>'}
复制代码

注意修改构建产物可以执行压缩操作,经一步的降低产物包的大小 minify: true,


运行验证

修改 app 的 build 命令

"scripts": {
        "build": "malita build",
        "dev": "malita dev",
        "g": "malita g",
        "serve": "cd dist && serve"
    },
复制代码


执行构建

cd examples/app
pnpm build
复制代码

生成 examples/app/dist,查看产物大小 300KB,服务端开启 gzip 的话,在100KB 左右。


模拟上线

cd examples/app/dist
npx serve
复制代码

tips: npx 会找你当前包里面的命令,如果找不到会帮你装这个命令。

➜  dist git:(master) ✗ npx serve
   ┌──────────────────────────────────────────────────┐
   │                                                  │
   │   Serving!                                       │
   │                                                  │
   │   - Local:            http://localhost:3000      │
   │   - On Your Network:  http://10.128.5.188:3000   │
   │                                                  │
   │   Copied local address to clipboard!             │
   │                                                  │
   └──────────────────────────────────────────────────┘
复制代码

用浏览器访问 http://localhost:3000 项目功能一切正常。


malita 框架发布

$ pnpm build
> @ build /Users/congxiaochen/Documents/malita
> pnpm -r --filter ./packages run build
Scope: 2 of 4 workspace projects
packages/malita build$ pnpm esbuild ./src/** --bundle --outdir=lib --platform=node --external:esbuild --loader:
[11 lines collapsed]
│   lib/server.js                85.5kb
│   lib/mock.js                  75.6kb
│   lib/config.js                 3.3kb
│   lib/hd.js                     2.8kb
│   lib/routes.js                 2.7kb
│   lib/html.js                   2.7kb
│   lib/appData.js                2.4kb
│   lib/constants.js              2.0kb
│   lib/index.js                   46b 
│ ⚡ Done in 790ms
└─ Done in 1.6s
packages/keepalive build$ tsc
└─ Done in 1.2s
$ cd packages/malita
$ npm publish
npm notice 📦  malita@0.0.5
npm notice === Tarball Details === 
npm notice name:          malita                                  
npm notice version:       0.0.5                                   
npm notice filename:      malita-0.0.5.tgz                        
npm notice package size:  12.6 MB                                 
npm notice unpacked size: 71.7 MB                                 
npm notice shasum:        6263479592f41475b844bfcac60cced2fb3b7f11
npm notice integrity:     sha512-lRD6fbMjEtLY5[...]HRqMMWDy6VYTQ==
npm notice total files:   102                                     
npm notice 
+ malita@0.0.5
复制代码


这个框架的产物还真的挺小的(捂脸,一个 alita 项目产物最小也要快 1M),突然觉得用它来支撑一些运营活动页还挺合适的。


感谢阅读,如果看完今天的内容,你有一种 “就这” 的感觉,说明你变强了。


源码归档

目录
相关文章
|
4天前
|
前端开发 JavaScript API
阿珊比较Vue和React:两大前端框架的较量
阿珊比较Vue和React:两大前端框架的较量
|
4天前
|
前端开发
Github项目分享——免费的画图工具drow,最新前端面试题整理
Github项目分享——免费的画图工具drow,最新前端面试题整理
|
6天前
|
资源调度 前端开发
编译第三方前端项目时候出现Syntax Error: TypeError: Cannot set properties of undefined (setting ‘parent‘)
编译第三方前端项目时候出现Syntax Error: TypeError: Cannot set properties of undefined (setting ‘parent‘)
54 0
|
6天前
|
开发框架 Dart 前端开发
【Flutter前端技术开发专栏】Flutter与React Native的对比与选择
【4月更文挑战第30天】对比 Flutter(Dart,强类型,Google支持,快速热重载,高性能渲染)与 React Native(JavaScript,庞大生态,热重载,依赖原生渲染),文章讨论了开发语言、生态系统、性能、开发体验、学习曲线、社区支持及项目选择因素。两者各有优势,选择取决于项目需求、团队技能和长期维护考虑。参考文献包括官方文档和性能比较文章。
【Flutter前端技术开发专栏】Flutter与React Native的对比与选择
|
3天前
|
JavaScript 前端开发 IDE
TypeScript在前端项目的渐进式采用策略
该文介绍了渐进式采用TypeScript在前端项目中的策略。首先,通过将JS文件扩展名改为TS并添加类型注解,如在`utils.js`中添加类型。接着,配置`tsconfig.json`,包括目标版本、模块系统、输出目录等。高级配置涉及路径别名、JSON导入、库文件等。然后,集成TypeScript到构建流程,如Webpack,安装`ts-loader`并调整配置。利用类型定义,包括安装第三方库的类型定义包,自定义类型定义或使用社区定义。最后,逐步迁移其他模块至TypeScript,强化类型检查,并确保IDE支持。
8 0
|
3天前
|
前端开发 JavaScript Java
《浅谈架构之路:前后端分离模式》 - 山人行 - 博客园,前端开发新手项目
《浅谈架构之路:前后端分离模式》 - 山人行 - 博客园,前端开发新手项目
|
3天前
|
前端开发 JavaScript Java
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
|
4天前
|
前端开发
React Hooks - useState 的使用方法和注意事项(1),web前端开发前景
React Hooks - useState 的使用方法和注意事项(1),web前端开发前景
|
4天前
|
SQL Oracle 前端开发
Oracle效率分析,Github标星25K+超火的前端实战项目
Oracle效率分析,Github标星25K+超火的前端实战项目
|
4天前
|
消息中间件 前端开发 JavaScript
【前端】websocket 讲解与项目中的使用
【前端】websocket 讲解与项目中的使用