Giter Site home page Giter Site logo

niexq / react-app-qiankun-main Goto Github PK

View Code? Open in Web Editor NEW
80.0 2.0 30.0 636 KB

🚀 基于create-react-app,qiankun构建并部署的测试用例(react主应用)Based on create-react-app, qiankun builds and deploys a simple main demo

Home Page: https://qiankun.xiaoqiang.tech

License: MIT License

HTML 17.51% CSS 20.32% JavaScript 62.18%
qiankun qiankun-example qiankun-demo qiankun-react-example qiankun-vue-example qiankun-react-demo create-react-app-qiankun vue-cli-qiankun react-qiankun vue-qiankun

react-app-qiankun-main's Introduction

💫 react-app-qiankun-main

基于create-react-app,qiankun构建并部署的测试用例(react主应用)

简体中文 | English

🚀 基于qiankun微前端实战+部署粗略笔记(跳过原理)

因业务需要,以下文字纯个人qiankun实战学习笔记,不谈原理只记操作过程,内容难免有纰漏部分,敬请不吝赐教批评指正。

✨ 目标场景

📝 预备知识点

🔧 技术栈

🍔 基座

🍟 react子应用

🌮 vue子应用

🚴‍♂️ 快速上手

🍔 基座

  • 1.初始化项目
npm init react-app react-app-qiankun-main
  • 2.安装qiankun
yarn add qiankun # 或者 npm i qiankun -S
  • 3.目录结构
react-app-qiankun-main
├── .env.local             // 本地环境
├── .env.development.local // 测试环境
├── .env.production.local  // 生产环境
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
   ├── favicon.ico
   ├── index.html
   └── manifest.json
└── src
    ├── components
         └── Loading.jsx
    ├── store
         └── store.js    // 主应用的全局状态
    ├── apps.js           // 子应用配置
    ├── App.css
    ├── App.js            // 基座布局,挂载子应用
    ├── App.test.js
    ├── index.css
    ├── index.js          // 主应用中注册微应用
    ├── logo.svg
    ├── reportWebVitals.js
    └── setupTests.js

🍔 基座(开撸代码)

  • 新增3个.env文件,主要配置不同环境的对应的域名

    • .env/.env.development.local(此处暂未区分本地和测试的域名,所有环境变量值都保持一致)
      REACT_APP_SUB_REACT=//localhost:2233/react
      REACT_APP_SUB_VUE=//localhost:3344/vue
      PORT=1122
    • .env.production.local (生产环境)
      REACT_APP_SUB_REACT = https://react.xiaoqiang.tech
      REACT_APP_SUB_VUE = https://vue.xiaoqiang.tech
  • 修改 index.html 挂载dom的默认id,防止与子应用id冲突

      // 默认root => main-root
      <div id="main-root"></div>
  • 新增store/store.js,配置主应用的全局状态

      import { initGlobalState } from 'qiankun';
    
      const initialState = {
        user: {
          name: 'qiankun'
        }
      };
    
      const actions = initGlobalState(initialState);
    
      actions.onGlobalStateChange((state, prev) => {
        for(const key in state) {
          initialState[key] = state[key];
        }
      })
    
      // 非官方api,https://github.com/umijs/qiankun/pull/729
      actions.getGlobalState = (key) => {
        return key ? initialState[key] : initialState;
      }
    
      export default actions;
  • 修改src/App.js,主要完成基座页面布局及增加挂载子应用的dom(id="subapp-viewport")

      function App(props) {
        // ...省略,详细可见源码
        return (
          <>
            <div className="mainapp">
              {/* 标题栏 */}
              <header className="mainapp-header">
                <ul className="mainapp-header-sidemenu">
                  {/* 侧边栏 省略,详细可见源码 */}
                </ul>
              </header>
              <div className="mainapp-main">
                {/* 子应用 */}
                <main id="subapp-viewport"></main>
              </div>
            </div>
          </>
        );
      }
  • 增加apps.js,子应用的配置

      import store from './store/store'
      const microApps = [
        {
          name: 'react',
          entry: process.env.REACT_APP_SUB_REACT,
          activeRule: '/react',
          container: '#subapp-viewport',
        },
        {
          name: 'vue',
          entry: process.env.REACT_APP_SUB_VUE,
          activeRule: '/vue',
          container: '#subapp-viewport',
        },
      ]
    
      const apps = microApps.map(item => {
        return {
          ...item,
          props: {
            routerBase: item.activeRule,
            getGlobalState: store.getGlobalState,
          }
        }
      })
    
      export default apps
  • 修改src/index.js,主应用中注册微(子)应用

      import React from 'react';
      import ReactDOM from 'react-dom';
      import './index.css';
      import App from './App';
      import { registerMicroApps, start, setDefaultMountApp } from 'qiankun';
      import apps from './apps'
    
      function render({ appContent, loading }) {
        const container = document.getElementById('main-root');
        ReactDOM.render(
          <React.StrictMode>
            <App loading={loading} content={appContent} />
          </React.StrictMode>,
          container,
        )
      }
    
      const loader = loading => render({ loading });
    
      render({ loading: true });
    
      const microApps = apps.map((app => ({
        ...app,
        loader,
      })))
      registerMicroApps(microApps, {
        beforeLoad: app => {
          console.log('before load app.name=====>>>>>', app.name)
        },
        beforeMount: [
          app => {
            console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name)
          }
        ],
        afterMount: [
          app => {
            console.log('[LifeCycle] after mount %c%s', 'color: green;', app.name)
          }
        ],
        afterUnmount: [
          app => {
            console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name)
          }
        ]
      })
    
      setDefaultMountApp('/react')
    
      start();
  • 本地启动

      npm start

🍟 react子应用

  • 1.初始化项目
npm init react-app react-app-qiankun-sub
  • 2.安装react-app-rewiredreact-router-dom
npm i react-app-rewired --save-dev
npm i react-router-dom --save
  • 3.目录结构
react-app-qiankun-sub
├── .env                 // 本地环境
├── config-overrides.js  // 覆盖create-react-app的webpack配置
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
   ├── favicon.ico
   ├── index.html
   └── manifest.json
└── src
    ├── components
         └── LibVersion.jsx
    ├── pages
         └── Home.jsx
    ├── public-path.js // __webpack_public_path__
    ├── App.css
    ├── App.js         // 子应用布局
    ├── App.test.js
    ├── index.css
    ├── index.js       // 子应用入口,挂载dom导出相应的生命周期钩子
    ├── logo.svg
    ├── reportWebVitals.js
    └── setupTests.js

🍟 react子应用(开撸代码)

  • 新增1个.env文件,主要配置本地环境

    此处PORT需要和基座REACT_APP_SUB_REACT端口保持一致

      PORT=2233
  • 修改 index.html 挂载dom的默认id,防止与基座及其他子应用id冲突

      // 默认root => sub-react-root
      <div id="sub-react-root"></div>
  • 新增src/public-path.jswebpack_public_path

      if (window.__POWERED_BY_QIANKUN__) {
        // eslint-disable-next-line no-undef
        __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
      }
  • 修改src/App.js,主要完成子应用页面布局(略,见源码)

  • 修改src/index.js,微(子)应用导出相应的生命周期钩子

      import './public-path';
      import React from 'react';
      import ReactDOM from 'react-dom';
      import './index.css';
      import App from './App';
    
      function getSubRootContainer(container) {
        return container ? container.querySelector('#sub-react-root') : document.querySelector('#sub-react-root');
      }
    
      function render(props) {
        const { container } = props;
        ReactDOM.render(
          <React.StrictMode>
            <App store={{...props}} />
          </React.StrictMode>,
          getSubRootContainer(container),
        );
      }
    
      function storeTest(props) {
        props.onGlobalStateChange((value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev), true);
        props.setGlobalState({
          ignore: props.name,
          user: {
            name: props.name,
          },
        });
      }
    
      if (!window.__POWERED_BY_QIANKUN__) {
        render({});
      }
    
      export async function bootstrap() {
        console.log('react app bootstraped');
      }
    
      export async function mount(props) {
        console.log('props from main framework', props);
        storeTest(props);
        render(props);
      }
    
      export async function unmount(props) {
        const { container } = props;
        ReactDOM.unmountComponentAtNode(getSubRootContainer(container));
      }
  • 增加config-overrides.js,覆盖create-react-app的webpack配置

      const { name } = require('./package');
      module.exports = {
        webpack: config => {
          config.output.library = `${name}-[name]`;
          config.output.libraryTarget = 'umd';
          config.output.jsonpFunction = `webpackJsonp_${name}`;
          return config;
        },
        devServer: (configFunction) => {
          return (proxy, allowedHost) => {
            const config = configFunction(proxy, allowedHost);
            config.historyApiFallback = true;
            config.open = false;
            config.hot = false;
            config.watchContentBase = false;
            config.liveReload = false;
            config.headers = {
              'Access-Control-Allow-Origin': '*',
            };
            return config;
          }
        }
      }
  • 修改 package.json

      "scripts": {
        -   "start": "react-scripts start",
        +   "start": "react-app-rewired start",
        -   "build": "react-scripts build",
        +   "build": "react-app-rewired build",
        -   "test": "react-scripts test",
        +   "test": "react-app-rewired test",
        "eject": "react-scripts eject"
      },
  • 本地启动

      npm start

🌮 vue子应用

  • 1.初始化项目
npm install -g @vue/cli-service-global
vue create vue-cli-qiankun-sub
  • 2.安装vue-router
npm i vue-router --save
  • 3.目录结构
vue-cli-qiankun-sub
├── .env                 // 本地环境
├── vue.config.js        // vue可选的配置文件
├── babel.config.js
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
   ├── favicon.ico
   ├── index.html
   └── manifest.json
└── src
    ├── components
        └── HelloWorld.vue
    ├── router
         └── index.js
    ├── views
         └── Home.vue
    ├── public-path.js  // __webpack_public_path__
    ├── App.vue         // 子应用布局
    └── main.js         // 子应用入口,挂载dom导出相应的生命周期钩子

🌮 vue子应用(开撸代码)

  • 新增1个.env文件,主要配置本地环境

    此处PORT需要和基座REACT_APP_SUB_VUE端口保持一致

      PORT=3344
  • 修改 index.html 挂载dom的默认id,防止与基座及其他子应用id冲突

      // 默认root => sub-vue-root
      <div id="sub-vue-root"></div>
  • 新增src/public-path.jswebpack_public_path

      if (window.__POWERED_BY_QIANKUN__) {
        // eslint-disable-next-line no-undef
        __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
      }
  • 修改src/App.vue,主要完成子应用页面布局(略,见源码)

  • 修改src/mian.js,微(子)应用导出相应的生命周期钩子

      import './public-path';
      import { createApp } from 'vue';
      import { createRouter, createWebHistory } from 'vue-router';
      import App from './App.vue';
      import routes from './router';
      import store from './store';
    
      let router = null;
      let instance = null;
      let history = null;
    
    
      function render(props = {}) {
        const { container } = props;
        history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/vue' : '/');
        router = createRouter({
          history,
          routes,
        });
    
        instance = createApp(App);
        instance.use(router);
        instance.use(store);
        instance.mount(container ? container.querySelector('#sub-vue-root') : '#sub-vue-root');
      }
    
      if (!window.__POWERED_BY_QIANKUN__) {
        render();
      }
    
      export async function bootstrap() {
        console.log('%c ', 'color: green;', 'vue3.0 app bootstraped');
      }
    
      function storeTest(props) {
        props.onGlobalStateChange &&
          props.onGlobalStateChange(
            (value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),
            true,
          );
        props.setGlobalState &&
          props.setGlobalState({
            ignore: props.name,
            user: {
              name: props.name,
            },
          });
      }
    
      export async function mount(props) {
        storeTest(props);
        render(props);
        instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChange;
        instance.config.globalProperties.$setGlobalState = props.setGlobalState;
      }
    
      export async function unmount() {
        instance.unmount();
        instance._container.innerHTML = '';
        instance = null;
        router = null;
        history.destroy();
      }
  • 增加vue.config.js配置文件

      const path = require('path');
      const { name } = require('./package');
    
      function resolve(dir) {
        return path.join(__dirname, dir);
      }
    
      const port = process.env.PORT;
    
      module.exports = {
        outputDir: 'dist',
        assetsDir: 'static',
        filenameHashing: true,
        devServer: {
          hot: true,
          disableHostCheck: true,
          port,
          overlay: {
            warnings: false,
            errors: true,
          },
          headers: {
            'Access-Control-Allow-Origin': '*',
          },
        },
        // 自定义webpack配置
        configureWebpack: {
          resolve: {
            alias: {
              '@': resolve('src'),
            },
          },
          output: {
            // 把子应用打包成 umd 库格式
            library: `${name}-[name]`,
            libraryTarget: 'umd',
            jsonpFunction: `webpackJsonp_${name}`,
          },
        },
      };
  • 修改 package.json

      "scripts": {
        +   "start": "vue-cli-service serve",
      },
  • 本地启动

      npm start

🏄 预览

以上操作完后,可以直接通过基座预览,子应用也可独立预览

基座预览

http://localhost:1122/

react子应用预览

http://localhost:2233/

vue子应用预览

http://localhost:3344/

🔨 部署

备选方案

  • 1.单域名部署;
// 基座:https://qiankun.xiaoqiang.tech
// react子应用:https://qiankun.xiaoqiang.tech/react
// vue子应用:https://qiankun.xiaoqiang.tech/vue
// 编译后服务器存储目录
react-app-qiankun
├── main
   └── index.html
├── react
   └── index.html
└── vue
    └── index.html
  • 2.多域名独立部署;(当篇笔记选择了多域名部署)
// 基座:https://qiankun.xiaoqiang.tech
// 编译后服务器项目独立存储目录
react-app-qiankun-main
  └── index.html
// react子应用:https://react.xiaoqiang.tech
// 编译后服务器项目独立存储目录
react-app-qiankun-sub
  └── index.html
// vue子应用:https://vue.xiaoqiang.tech
// 编译后服务器项目独立存储目录
vue-cli-qiankun-sub
└── index.html

部署(以下只初略记录部署过程,过于简陋)

// 基座:react-app-qiankun-main 存储到 https://github.com/niexq/react-app-qiankun-main
// react子应用:react-app-qiankun-sub 存储到 https://github.com/niexq/react-app-qiankun-sub
// vue子应用:vue-cli-qiankun-sub 存储到 https://github.com/niexq/vue-cli-qiankun-sub
// 详细配置步骤略
// github webHooks设置
// jenkins构建部分执行shell
BUILD_ID=dontKillMe
cd /var/jenkins_home/workspace/react-app-qiankun-main
npm install
npm run build
rm -rf /srv/www/react-app-qiankun-main
cp -rf /var/jenkins_home/workspace/react-app-qiankun-main/build /srv/www/react-app-qiankun-main/
  • 使用nginx代理 nginx.conf
user root;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    #include /etc/nginx/conf.d/*.conf;

    server {
        listen 443;
        server_name qiankun.xiaoqiang.tech; # 你的域名
        ssl on;
        root www/react-app-qiankun-main; # 前台文件存放文件夹,可改成别的
        index index.html index.htm; # 上面配置的文件夹里面的index.html
        ssl_certificate cert/5543142_qiankun.xiaoqiang.tech.pem;   #将domain name.pem替换成您证书的文件名。
        ssl_certificate_key cert/5543142_qiankun.xiaoqiang.tech.key;   #将domain name.key替换成您证书的密钥文件名。
        ssl_session_timeout 5m;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        location / {
          # 用于配合 browserHistory使用
          try_files $uri $uri/ /index.html;
          # root /srv/www/react-app-qiankun-main;
          # index index.html index.htm;
        }
    }

    server {
        listen 443;
        server_name react.xiaoqiang.tech; # 你的域名
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
        if ($request_method = 'OPTIONS') {
            return 204;
        }
        ssl on;
        root www/react-app-qiankun-sub; # 前台文件存放文件夹,可改成别的
        index index.html index.htm; # 上面配置的文件夹里面的index.html
        ssl_certificate cert/4325684_react.xiaoqiang.tech.pem;   #将domain name.pem替换成您证书的文件名。
        ssl_certificate_key cert/4325684_react.xiaoqiang.tech.key;   #将domain name.key替换成您证书的密钥文件名。
        ssl_session_timeout 5m;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        location / {
          # 用于配合 browserHistory使用
          try_files $uri $uri/ /index.html;
          # root /srv/www/react-app-qiankun-sub;
          # index index.html index.htm;
        }
    }

    server {
        listen 443;
        server_name vue.xiaoqiang.tech; # 你的域名
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
        if ($request_method = 'OPTIONS') {
            return 204;
        }
        ssl on;
        root www/vue-cli-qiankun-sub; # 前台文件存放文件夹,可改成别的
        index index.html index.htm; # 上面配置的文件夹里面的index.html
        ssl_certificate cert/5556275_vue.xiaoqiang.tech.pem;   #将domain name.pem替换成您证书的文件名。
        ssl_certificate_key cert/5556275_vue.xiaoqiang.tech.key;   #将domain name.key替换成您证书的密钥文件名。
        ssl_session_timeout 5m;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        location / {
          # 用于配合 browserHistory使用
          try_files $uri $uri/ /index.html;
          # root /srv/www/vue-cli-qiankun-sub;
          # index index.html index.htm;
        }
    }
}

docker运行nginx命令,重点关注-v 挂载目录

docker run --name nginx -p 80:80 -p 443:443 -v /root/nginx/config/nginx.conf:/etc/nginx/nginx.conf -v /root/nginx/cert:/etc/nginx/cert -v /root/nginx/logs:/var/log/nginx -v /srv/www/react-app-qiankun-main:/etc/nginx/www/react-app-qiankun-main -v /srv/www/react-app-qiankun-sub:/etc/nginx/www/react-app-qiankun-sub -v /srv/www/vue-cli-qiankun-sub:/etc/nginx/www/vue-cli-qiankun-sub --restart=always -d nginx:stable

🌴 总结

没有总结,遇到的问题太多,笔记总结的太杂,后期再整理分享

线上预览地址:https://qiankun.xiaoqiang.tech

子应用线上也可独立预览

react子应用预览:https://react.xiaoqiang.tech

vue子应用预览:https://vue.xiaoqiang.tech

源码地址:https://github.com/niexq/react-app-qiankun-main

🧩 参考链接

qiankun

qiankun-example

qiankun 微前端方案实践及总结

💯 跳过上述繁琐步骤是否可行

智慧的选择

🏆 写在最后

能坚持到最后的都是勇士,感谢阅读,欢迎star鼓励

⭐️ Star

Star History Chart

react-app-qiankun-main's People

Contributors

niexq avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

react-app-qiankun-main's Issues

您好,咨询!

公共的登录功能加入集成在基座中。打开基座域名,我登录状态可以分发,我要单独进入子应用的域名,怎么加载登录组件呢

主应用 npm start 时报错

image


Compiled with problems:
×
ERROR
Cannot find module 'classnames'
at webpackMissingModule (http://localhost:1122/static/js/bundle.js:20:50)
at ./src/App.js (http://localhost:1122/static/js/bundle.js:20:135)
at options.factory (http://localhost:1122/static/js/bundle.js:54228:31)
at webpack_require (http://localhost:1122/static/js/bundle.js:53674:33)
at fn (http://localhost:1122/static/js/bundle.js:53885:21)
at ./src/index.js (http://localhost:1122/static/js/bundle.js:353:62)
at options.factory (http://localhost:1122/static/js/bundle.js:54228:31)
at webpack_require (http://localhost:1122/static/js/bundle.js:53674:33)
at http://localhost:1122/static/js/bundle.js:54810:37
at http://localhost:1122/static/js/bundle.js:54812:12
ERROR in ./src/App.js 9:0-36
Module not found: Error: Can't resolve 'classnames' in '/Users/mac/Desktop/init/src'

react子应用嵌套vue子应用有问题

export default function() {
const [visible, setVisible] = useState(false);
const curRef = useRef(null)

useEffect(() => {
return loadMicroApp({
name: "vue",
entry: "//localhost:3344/vue",
container: "#aa",
});
},[])

return (
<>


<Button onClick={() => setVisible(true)}>CLICK ME
<Modal
visible={visible}
onOk={() => setVisible(false)}
onCancel={() => setVisible(false)}
title="qiankun"
>
Probably the most complete micro-frontends solution you ever met

</>
);
}

在qiankun-demo/react-app-qiankun-sub/src/components/HelloModal.jsx文件里加上,就显示不出嵌套的子应用

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.