├── .npmrc ├── glass-easel-miniprogram-template ├── .gitignore ├── src │ ├── components │ │ ├── view │ │ │ ├── view.wxml │ │ │ ├── view.json │ │ │ ├── view.wxss │ │ │ └── view.ts │ │ └── image │ │ │ ├── image.wxml │ │ │ ├── image.json │ │ │ ├── image.wxss │ │ │ └── image.ts │ ├── app.wxss │ ├── app.ts │ ├── resources │ │ └── logo_256.png │ ├── pages │ │ └── index │ │ │ ├── index.json │ │ │ ├── index.wxss │ │ │ ├── index.ts │ │ │ └── index.wxml │ └── index.html ├── typings │ └── miniprogram.d.ts ├── webpack.dev.config.js ├── .eslintrc.js ├── tsconfig.json ├── README.md ├── package.json └── webpack.config.js ├── .gitignore ├── glass-easel ├── .eslintignore ├── .npmignore ├── .gitignore ├── tests │ ├── legacy │ │ └── README.md │ ├── tmpl │ │ └── dev_mode.test.ts │ ├── core │ │ ├── data_proxy.test.ts │ │ ├── class_list.test.ts │ │ └── relation.test.ts │ └── types │ │ └── createElement.test.ts ├── jest.config.js ├── tsconfig.json ├── jest.dts.config.js ├── jest.unit.config.js ├── guide │ └── zh_CN │ │ ├── data_management │ │ ├── pure_data_pattern.md │ │ ├── property_early_init.md │ │ ├── data_deep_copy.md │ │ ├── data_observer.md │ │ └── advanced_update.md │ │ ├── advanced │ │ ├── error_listener.md │ │ ├── binding_map_update.md │ │ ├── build_args.md │ │ ├── template_engine.md │ │ ├── component_filter.md │ │ ├── custom_backend.md │ │ ├── external_component.md │ │ └── component_space.md │ │ ├── interaction │ │ ├── component_path.md │ │ ├── placeholder.md │ │ ├── behavior.md │ │ ├── generic.md │ │ ├── trait_behavior.md │ │ ├── slot.md │ │ └── template_import.md │ │ ├── styling │ │ ├── external_class.md │ │ ├── style_isolation.md │ │ └── virtual_host.md │ │ ├── basic │ │ ├── method.md │ │ ├── lifetime.md │ │ └── beginning.md │ │ ├── tree │ │ ├── element_iterator.md │ │ ├── mutation_observer.md │ │ ├── selector.md │ │ └── node_tree_modification.md │ │ └── index.md ├── README.md ├── src │ ├── backend │ │ ├── index.ts │ │ ├── composed_backend_protocol.ts │ │ ├── shared.ts │ │ ├── domlike_backend_protocol.ts │ │ └── backend_protocol.ts │ ├── render.ts │ ├── external_shadow_tree.ts │ ├── type_symbol.ts │ ├── trait_behaviors.ts │ ├── data_utils.ts │ ├── virtual_node.ts │ ├── template_engine.ts │ ├── warning.ts │ └── dev_tools.ts └── package.json ├── glass-easel-miniprogram-typescript ├── src │ ├── index.ts │ └── cli.ts ├── .gitignore ├── .eslintignore ├── tsconfig.json ├── sample-template-backend-config.d.ts ├── package.json └── README.md ├── glass-easel-shadow-sync ├── .eslintignore ├── .gitignore ├── tests │ ├── core │ │ ├── event.test.ts │ │ ├── virtual.test.ts │ │ ├── component.test.ts │ │ ├── placehoder.test.ts │ │ ├── structure.test.ts │ │ ├── binding_map.test.ts │ │ └── slot.test.ts │ └── spec │ │ └── replay.test.ts ├── tsconfig.json ├── package.json ├── jest.config.js ├── src │ ├── template_engine.ts │ └── utils.ts └── rollup.config.mjs ├── logo_256.png ├── glass-easel-miniprogram-adapter ├── .eslintignore ├── .npmignore ├── .gitignore ├── src │ ├── utils.ts │ ├── builder │ │ └── index.ts │ ├── index.ts │ ├── media_query.ts │ ├── resize.ts │ ├── env.ts │ └── types.ts ├── tsconfig.json ├── jest.config.js ├── tests │ ├── base │ │ └── env.ts │ └── data_update.test.ts ├── README.md ├── package.json └── rollup.config.ts ├── glass-easel-stylesheet-compiler ├── .gitignore ├── package.json ├── Cargo.toml ├── README.md └── src │ ├── step.rs │ ├── output.rs │ └── error.rs ├── glass-easel-template-compiler ├── .gitignore ├── src │ ├── lib.rs │ ├── path.rs │ ├── entities.rs │ ├── stringify │ │ └── mod.rs │ ├── escape.rs │ └── binding_map.rs ├── main.js ├── tests │ ├── stringify.rs │ ├── group.rs │ └── script.rs ├── module.js ├── README.md ├── Cargo.toml ├── package.json └── cbindgen.toml ├── glass-easel-miniprogram-webpack-plugin ├── .npmignore ├── .eslintignore ├── .gitignore ├── tsconfig.json ├── helpers.ts ├── wxml_loader.js ├── package.json └── wxss_loader.js ├── .gitattributes ├── .eslintignore ├── Cargo.toml ├── pnpm-workspace.yaml ├── .prettierrc.js ├── tsconfig.json ├── LICENSE ├── package.json ├── deprecate.js ├── logo.svg ├── .github └── workflows │ ├── build.yml │ └── pages.yml └── .eslintrc.js /.npmrc: -------------------------------------------------------------------------------- 1 | registry= https://registry.npmjs.org/ -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /target 3 | /node_modules 4 | /package-lock.json 5 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/components/view/view.wxml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /glass-easel/.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /docs 4 | /coverage 5 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/app.wxss: -------------------------------------------------------------------------------- 1 | /* this is the global stylesheet */ 2 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-typescript/src/index.ts: -------------------------------------------------------------------------------- 1 | export * as server from './server' 2 | -------------------------------------------------------------------------------- /glass-easel/.npmignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /node_modules 3 | /docs 4 | /coverage 5 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/components/image/image.wxml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /docs 4 | /coverage 5 | -------------------------------------------------------------------------------- /logo_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wechat-miniprogram/glass-easel/HEAD/logo_256.png -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /docs 4 | /coverage 5 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/components/view/view.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } 4 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-typescript/.gitignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /node_modules 3 | /dist 4 | -------------------------------------------------------------------------------- /glass-easel/.gitignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /node_modules 3 | /dist 4 | /docs 5 | /coverage 6 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/components/image/image.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } 4 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/components/view/view.wxss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-typescript/.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /docs 4 | /coverage 5 | -------------------------------------------------------------------------------- /glass-easel-stylesheet-compiler/.gitignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /pkg 3 | /pkg-nodejs 4 | /pkg-web 5 | -------------------------------------------------------------------------------- /glass-easel-template-compiler/.gitignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /pkg 3 | /pkg-nodejs 4 | /pkg-web 5 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/.npmignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /node_modules 3 | /docs 4 | /coverage 5 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/components/image/image.wxss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/.gitignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /node_modules 3 | /dist 4 | /docs 5 | /coverage 6 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/.gitignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /node_modules 3 | /dist 4 | /docs 5 | /coverage 6 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-webpack-plugin/.npmignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /node_modules 3 | /docs 4 | /coverage 5 | -------------------------------------------------------------------------------- /glass-easel/tests/legacy/README.md: -------------------------------------------------------------------------------- 1 | # Legacy tests 2 | 3 | These tests are imported from the legacy framework. 4 | -------------------------------------------------------------------------------- /glass-easel/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | projects: ['./jest.unit.config.js', './jest.dts.config.js'], 3 | } 4 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-webpack-plugin/.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /docs 4 | /coverage 5 | /index.js 6 | /helpers.js 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.md text eol=lf 4 | *.js text eol=lf 5 | *.mjs text eol=lf 6 | *.ts text eol=lf 7 | *.json text eol=lf 8 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /target 2 | /node_modules 3 | /glass-easel-miniprogram-template 4 | /glass-easel-template-compiler 5 | /glass-easel-stylesheet-compiler 6 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-webpack-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /node_modules 3 | /dist 4 | /docs 5 | /coverage 6 | /index.js 7 | /helpers.js 8 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/components/image/image.ts: -------------------------------------------------------------------------------- 1 | export default Component({ 2 | properties: { 3 | src: String, 4 | }, 5 | data: {}, 6 | }) 7 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/app.ts: -------------------------------------------------------------------------------- 1 | // this file is always executed on startup 2 | 3 | // eslint-disable-next-line no-console 4 | console.info('App started') 5 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/src/utils.ts: -------------------------------------------------------------------------------- 1 | export const guid = (): string => 2 | Math.floor((1 + Math.random()) * 0x100000000) 3 | .toString(16) 4 | .slice(1) 5 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/resources/logo_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wechat-miniprogram/glass-easel/HEAD/glass-easel-miniprogram-template/src/resources/logo_256.png -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "view": "/components/view/view", 4 | "image": "/components/image/image" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | .logo { 2 | width: 256px; 3 | margin: 0 auto; 4 | } 5 | 6 | .hello { 7 | margin: 20px; 8 | text-align: center; 9 | } 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "glass-easel-template-compiler", 4 | "glass-easel-stylesheet-compiler", 5 | ] 6 | resolver = "2" 7 | 8 | [profile.release] 9 | opt-level = 3 10 | lto = true 11 | -------------------------------------------------------------------------------- /glass-easel/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ 4 | "*.ts", 5 | "src/**/*.ts", 6 | "tests/**/*.ts", 7 | "examples/**/*.ts" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-webpack-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS" 5 | }, 6 | "include": [ 7 | "*.ts" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/pages/index/index.ts: -------------------------------------------------------------------------------- 1 | export default Page({ 2 | data: { 3 | showAgain: false, 4 | }, 5 | helloTap() { 6 | this.setData({ 7 | showAgain: true, 8 | }) 9 | }, 10 | }) 11 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ 4 | "*.ts", 5 | "src/**/*.ts", 6 | "tests/**/*.ts", 7 | "examples/**/*.ts" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/typings/miniprogram.d.ts: -------------------------------------------------------------------------------- 1 | import type { PageConstructor, ComponentConstructor } from 'glass-easel-miniprogram-adapter' 2 | 3 | declare global { 4 | const Page: PageConstructor 5 | const Component: ComponentConstructor 6 | } 7 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS", 5 | "outDir": "dist" 6 | }, 7 | "include": [ 8 | "src/*.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /glass-easel/jest.dts.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: { 3 | color: 'blue', 4 | name: 'types', 5 | }, 6 | roots: ['tests'], 7 | runner: 'jest-runner-tsd', 8 | testMatch: ['**/types/**/?(*.)+(spec|test).[jt]s?(x)'], 9 | } 10 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-webpack-plugin/helpers.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | export const escapeJsString = (str: string) => 4 | str.replace(/["'\\\r\n`]/g, (c) => { 5 | if (c === '\r') return '\\r' 6 | if (c === '\n') return '\\n' 7 | return `\\${c}` 8 | }) 9 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/tests/core/event.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import * as coreEnv from 'glass-easel/tests/base/env' 3 | import { shadowSyncBackend } from '../base/env' 4 | 5 | ;(coreEnv as any).shadowBackend = shadowSyncBackend 6 | 7 | require('../../../glass-easel/tests/tmpl/event.test') 8 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/tests/core/virtual.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import * as coreEnv from 'glass-easel/tests/base/env' 3 | import { shadowSyncBackend } from '../base/env' 4 | 5 | ;(coreEnv as any).shadowBackend = shadowSyncBackend 6 | 7 | require('../../../glass-easel/tests/legacy/virtual.test') 8 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/tests/core/component.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import * as coreEnv from 'glass-easel/tests/base/env' 3 | import { shadowSyncBackend } from '../base/env' 4 | 5 | ;(coreEnv as any).shadowBackend = shadowSyncBackend 6 | 7 | require('../../../glass-easel/tests/legacy/component.test') 8 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/tests/core/placehoder.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import * as coreEnv from 'glass-easel/tests/base/env' 3 | import { shadowSyncBackend } from '../base/env' 4 | 5 | ;(coreEnv as any).shadowBackend = shadowSyncBackend 6 | 7 | require('../../../glass-easel/tests/core/placeholder.test') 8 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/tests/core/structure.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import * as coreEnv from 'glass-easel/tests/base/env' 3 | import { shadowSyncBackend } from '../base/env' 4 | 5 | ;(coreEnv as any).shadowBackend = shadowSyncBackend 6 | 7 | require('../../../glass-easel/tests/tmpl/structure.test') 8 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/tests/core/binding_map.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import * as coreEnv from 'glass-easel/tests/base/env' 3 | import { shadowSyncBackend } from '../base/env' 4 | 5 | ;(coreEnv as any).shadowBackend = shadowSyncBackend 6 | 7 | require('../../../glass-easel/tests/tmpl/binding_map.test') 8 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | 3 | const config = require('./webpack.config') 4 | 5 | config[0].mode = 'development' 6 | config[0].resolve.alias['glass-easel'] = 'glass-easel/dist/glass_easel.dev.all.es.js' 7 | 8 | module.exports = config 9 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello world! 6 | 7 | 10 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "glass-easel": ["../glass-easel/src"] 6 | } 7 | }, 8 | "include": [ 9 | "src/**/*.ts", 10 | "tests/**/*.ts", 11 | "examples/**/*.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/src/builder/index.ts: -------------------------------------------------------------------------------- 1 | export { BehaviorBuilder } from './behavior_builder' 2 | export type { DefaultBehaviorBuilder } from './behavior_builder' 3 | export { ComponentBuilder } from './component_builder' 4 | export type { DefaultComponentBuilder } from './component_builder' 5 | export { BuilderContext } from './type_utils' 6 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "glass-easel" 3 | - "glass-easel-miniprogram-adapter" 4 | - "glass-easel-miniprogram-webpack-plugin" 5 | - "glass-easel-shadow-sync" 6 | - "glass-easel-miniprogram-template" 7 | - "glass-easel-miniprogram-typescript" 8 | - "glass-easel-template-compiler" 9 | - "glass-easel-stylesheet-compiler" 10 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | ecmaVersion: 9, 5 | sourceType: 'module', 6 | }, 7 | parser: '@typescript-eslint/parser', 8 | plugins: ['@typescript-eslint', 'import', 'promise'], 9 | globals: { 10 | Component: true, 11 | Page: true, 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/tests/core/slot.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import * as coreEnv from 'glass-easel/tests/base/env' 3 | import { shadowSyncBackend } from '../base/env' 4 | 5 | ;(coreEnv as any).shadowBackend = shadowSyncBackend 6 | 7 | require('../../../glass-easel/tests/legacy/slot.test') 8 | require('../../../glass-easel/tests/core/slot.test') 9 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/src/index.ts: -------------------------------------------------------------------------------- 1 | export * as glassEasel from 'glass-easel' 2 | export { AssociatedBackend, Root } from './backend' 3 | export * as component from './component' 4 | export * as behavior from './behavior' 5 | export * as builder from './builder' 6 | export { MiniProgramEnv } from './env' 7 | export * from './space' 8 | export * as types from './types' 9 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest/presets/js-with-babel', 3 | transform: { 4 | '^.+\\.ts$': [ 5 | 'ts-jest', 6 | { 7 | tsconfig: 'tsconfig.json', 8 | }, 9 | ], 10 | }, 11 | roots: ['tests'], 12 | testEnvironment: 'jsdom', 13 | collectCoverageFrom: ['src/**/*.ts'], 14 | } 15 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "module": "es6", 5 | "target": "es5", 6 | "esModuleInterop": true, 7 | "moduleResolution": "node", 8 | "lib": ["ES6", "ES7", "DOM", "ESNext"] 9 | }, 10 | "include": [ 11 | "src/**/*.ts", 12 | "typings" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-typescript/sample-template-backend-config.d.ts: -------------------------------------------------------------------------------- 1 | export type GlassEaselTemplateBackendConfig = { 2 | name: 'sample' 3 | description: 'An example of template backend configuration.' 4 | majorVersion: 1 5 | minorVersion: 0 6 | } 7 | 8 | export type ComponentProperties = { 9 | div: { 10 | hidden: boolean 11 | } 12 | img: { 13 | src: string 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 100, 3 | tabWidth: 2, 4 | useTabs: false, 5 | semi: false, 6 | singleQuote: true, 7 | quoteProps: 'as-needed', 8 | trailingComma: 'all', 9 | bracketSpacing: true, 10 | arrowParens: 'always', 11 | requirePragma: false, 12 | insertPragma: false, 13 | proseWrap: 'preserve', 14 | endOfLine: 'lf', 15 | embeddedLanguageFormatting: 'auto', 16 | } 17 | -------------------------------------------------------------------------------- /glass-easel/jest.unit.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest/presets/js-with-babel', 3 | transform: { 4 | '^.+\\.ts$': [ 5 | 'ts-jest', 6 | { 7 | tsconfig: 'tsconfig.json', 8 | }, 9 | ], 10 | }, 11 | roots: ['tests'], 12 | testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)', '!**/types/**'], 13 | testEnvironment: 'jsdom', 14 | collectCoverageFrom: ['src/**/*.ts'], 15 | } 16 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glass-easel-shadow-sync", 3 | "version": "0.17.2", 4 | "main": "dist/glass-easel-shadow-sync.js", 5 | "scripts": { 6 | "build": "rollup -c rollup.config.mjs", 7 | "test": "jest -c jest.config.js" 8 | }, 9 | "dependencies": { 10 | "glass-easel": "workspace:*" 11 | }, 12 | "devDependencies": { 13 | "glass-easel-template-compiler": "workspace:*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /glass-easel-template-compiler/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::needless_borrow)] 2 | 3 | #[allow(unused_imports)] 4 | #[macro_use] 5 | extern crate log; 6 | #[macro_use] 7 | extern crate lazy_static; 8 | 9 | mod binding_map; 10 | mod group; 11 | pub mod parse; 12 | pub mod stringify; 13 | pub use group::*; 14 | #[cfg(feature = "c_bindings")] 15 | pub mod cbinding; 16 | mod entities; 17 | mod escape; 18 | mod js_bindings; 19 | mod path; 20 | mod proc_gen; 21 | -------------------------------------------------------------------------------- /glass-easel-shadow-sync/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest/presets/js-with-babel', 3 | transform: { 4 | '^.+\\.ts$': [ 5 | 'ts-jest', 6 | { 7 | tsconfig: 'tsconfig.json', 8 | }, 9 | ], 10 | }, 11 | moduleNameMapper: { 12 | '^glass-easel$': '/../glass-easel/src', 13 | }, 14 | roots: ['tests'], 15 | testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)', '!**/types/**'], 16 | testEnvironment: 'jsdom', 17 | collectCoverageFrom: ['src/**/*.ts'], 18 | } 19 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/README.md: -------------------------------------------------------------------------------- 1 | # glass-easel-miniprogram-template 2 | 3 | The template mini-program code for the glass-easel project. 4 | 5 | Refer to the [glass-easel](https://github.com/wechat-miniprogram/glass-easel) project for further details. 6 | 7 | ## Build 8 | 9 | `nodejs` toolchain should be globally installed. 10 | 11 | Install dependencies: 12 | 13 | ```sh 14 | npm install 15 | ``` 16 | 17 | Build: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | Then open `dist/index.html` in the browser. 24 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-webpack-plugin/wxml_loader.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { escapeJsString } = require('./helpers') 3 | 4 | module.exports = function (src, prevMap, meta) { 5 | const { addTemplate } = this.query 6 | const { compPath, deps, codeRoot } = addTemplate(src, this.currentModule) 7 | const requires = deps.map((x) => { 8 | const p = path.join(codeRoot, `${x}.wxml`) 9 | return `require('${escapeJsString(p)}');` 10 | }) 11 | return ` 12 | ${requires.join('')} 13 | module.exports = '${escapeJsString(compPath)}' 14 | ` 15 | } 16 | -------------------------------------------------------------------------------- /glass-easel/guide/zh_CN/data_management/pure_data_pattern.md: -------------------------------------------------------------------------------- 1 | # 纯数据字段 2 | 3 | 通过组件选项 `pureDataPattern` 可以使得一些数据字段不能用于模板上。这个选项接受一个正则表达式,符合这个正则表达式的字段名不能用于模板。 4 | 5 | ```js 6 | export const myComponent = componentSpace.defineComponent({ 7 | options: { 8 | // 所有以 _ 开头的字段都不能用于模板 9 | pureDataPattern: /^_/, 10 | }, 11 | // 模板上的纯数据字段将视为 undefined 12 | template: compileTemplate(` 13 |
{{ _a }}
14 | `), 15 | data: { 16 | _a: 1, 17 | }, 18 | }) 19 | ``` 20 | 21 | 使用 `pureDataPattern` 通常不会带来性能方面的影响。但如果通过 `dataDeepCopy` 禁用数据拷贝, `pureDataPattern` 可能仍然会带来部分数据拷贝开销。 22 | -------------------------------------------------------------------------------- /glass-easel-template-compiler/main.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path') 2 | const fs = require('node:fs') 3 | const { fileURLToPath } = require('node:url') 4 | const bg = require('./pkg/glass_easel_template_compiler_bg.cjs.js') 5 | 6 | const bytes = fs.readFileSync( 7 | path.resolve(__dirname, './pkg/glass_easel_template_compiler_bg.wasm'), 8 | ) 9 | 10 | const wasmModule = new WebAssembly.Module(bytes) 11 | const wasmInstance = new WebAssembly.Instance(wasmModule, { 12 | './glass_easel_template_compiler_bg.js': bg, 13 | }) 14 | 15 | bg.__wbg_set_wasm(wasmInstance.exports) 16 | 17 | module.exports = bg 18 | -------------------------------------------------------------------------------- /glass-easel-template-compiler/tests/stringify.rs: -------------------------------------------------------------------------------- 1 | use glass_easel_template_compiler::{stringify::Stringifier, TmplGroup}; 2 | 3 | #[test] 4 | fn stringifier() { 5 | const SRC_A: &str = r#"
Hello world!
"#; 6 | let mut group = TmplGroup::new(); 7 | group.add_tmpl("a", SRC_A); 8 | let tmpl = group.get_tree("a").unwrap(); 9 | let mut out = String::new(); 10 | Stringifier::new(&mut out, "a", Some(SRC_A), Default::default()) 11 | .run(tmpl) 12 | .unwrap(); 13 | assert_eq!( 14 | out, 15 | "\n
\n Hello world! \n
\n" 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /glass-easel/README.md: -------------------------------------------------------------------------------- 1 | # glass-easel 2 | 3 | This is the core module of the glass-easel project. 4 | 5 | Refer to the [glass-easel](https://github.com/wechat-miniprogram/glass-easel) project for further details. 6 | 7 | ## Build 8 | 9 | `nodejs` toolchain should be globally installed. 10 | 11 | Install dependencies and prepare environment: 12 | 13 | ```sh 14 | npm install 15 | npm run init-dev 16 | ``` 17 | 18 | Build: 19 | 20 | ```sh 21 | npm run build 22 | ``` 23 | 24 | Build Doc: 25 | 26 | ```sh 27 | npm run doc 28 | ``` 29 | 30 | Test: 31 | 32 | ```sh 33 | npm test 34 | ``` 35 | 36 | Test coverage: 37 | 38 | ```sh 39 | npm run coverage 40 | ``` 41 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/src/components/view/view.ts: -------------------------------------------------------------------------------- 1 | import { StyleSegmentIndex } from 'glass-easel' 2 | 3 | export default Component({ 4 | properties: { 5 | hidden: Boolean, 6 | }, 7 | data: {}, 8 | observers: { 9 | hidden(hidden: boolean) { 10 | // `this._$` is the underlying glass-easel element 11 | // (this cannot be retrieved in MiniProgram environment) 12 | const glassEaselElement = this._$ 13 | if (hidden) { 14 | glassEaselElement.setNodeStyle('display: none', StyleSegmentIndex.TEMP_EXTRA) 15 | } else { 16 | glassEaselElement.setNodeStyle('', StyleSegmentIndex.TEMP_EXTRA) 17 | } 18 | }, 19 | }, 20 | }) 21 | -------------------------------------------------------------------------------- /glass-easel/src/backend/index.ts: -------------------------------------------------------------------------------- 1 | import type * as backend from './backend_protocol' 2 | import type * as composedBackend from './composed_backend_protocol' 3 | import type * as domlikeBackend from './domlike_backend_protocol' 4 | 5 | export * from './shared' 6 | export * as backend from './backend_protocol' 7 | export * as composedBackend from './composed_backend_protocol' 8 | export * as domlikeBackend from './domlike_backend_protocol' 9 | 10 | export type GeneralBackendContext = 11 | | backend.Context 12 | | composedBackend.Context 13 | | domlikeBackend.Context 14 | 15 | export type GeneralBackendElement = 16 | | backend.Element 17 | | composedBackend.Element 18 | | domlikeBackend.Element 19 | -------------------------------------------------------------------------------- /glass-easel/src/render.ts: -------------------------------------------------------------------------------- 1 | import { type GeneralBackendContext } from './backend' 2 | import { type Element } from './element' 3 | import { safeCallback } from './func_arr' 4 | 5 | const triggerRenderOnContext = ( 6 | context: GeneralBackendContext, 7 | cb: ((err: Error | null) => void) | null, 8 | ) => { 9 | context.render(() => { 10 | if (typeof cb === 'function') { 11 | safeCallback('render', cb, context, [null]) 12 | } 13 | }) 14 | } 15 | 16 | export const triggerRender = (element: Element, callback?: (err: Error | null) => void) => { 17 | const context = element.getBackendContext() 18 | if (context) { 19 | triggerRenderOnContext(context, callback || null) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /glass-easel-template-compiler/module.js: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | import fs from 'node:fs' 3 | import { fileURLToPath } from 'node:url' 4 | import * as bg from './pkg/glass_easel_template_compiler_bg.js' 5 | 6 | const __filename = fileURLToPath(import.meta.url) 7 | const __dirname = path.dirname(__filename) 8 | 9 | const bytes = fs.readFileSync( 10 | path.resolve(__dirname, './pkg/glass_easel_template_compiler_bg.wasm'), 11 | ) 12 | 13 | const wasmModule = new WebAssembly.Module(bytes) 14 | const wasmInstance = new WebAssembly.Instance(wasmModule, { 15 | './glass_easel_template_compiler_bg.js': bg, 16 | }) 17 | 18 | bg.__wbg_set_wasm(wasmInstance.exports) 19 | 20 | export * from './pkg/glass_easel_template_compiler_bg.js' 21 | -------------------------------------------------------------------------------- /glass-easel/guide/zh_CN/data_management/property_early_init.md: -------------------------------------------------------------------------------- 1 | # 组件初始化策略 2 | 3 | 组件实例初始化流程有两种: 4 | 5 | 1. 总是以自己定义的数据来初始化模板、触发 created 生命周期,然后如有必要,应用外部设置的组件属性、触发数据监听器、再更新一次模板; 6 | 2. 先在自己定义的数据的基础上,应用外部设置的组件属性、触发数据监听器,然后初始化模板、触发 created 生命周期。 7 | 8 | 前者的好处是数据监听器永远在 created 生命周期之后触发,逻辑时序比较稳定;坏处是常常需要一次额外的模板更新,性能相对较差。 9 | 10 | glass-easel 目前以前者为默认的初始化方式,通过设置 `propertyEarlyInit` 选项可以改为后者: 11 | 12 | ```js 13 | export const childComponent = componentSpace.defineComponent({ 14 | options: { 15 | propertyEarlyInit: true, 16 | }, 17 | data: { 18 | a: 1, 19 | }, 20 | observers: { 21 | a() { 22 | // 可能早于 created 生命周期触发 23 | } 24 | }, 25 | lifetimes: { 26 | created() { 27 | // 可能晚于 observers 触发 28 | }, 29 | }, 30 | }) 31 | ``` 32 | -------------------------------------------------------------------------------- /glass-easel-template-compiler/README.md: -------------------------------------------------------------------------------- 1 | # glass-easel-template-compiler 2 | 3 | The template compiler for the glass-easel project. 4 | 5 | Refer to the [glass-easel](https://github.com/wechat-miniprogram/glass-easel) project for further details. 6 | 7 | ## Build 8 | 9 | `rust` toolchain and `wasm-pack` should be globally installed. 10 | 11 | Build WebAssembly binary: 12 | 13 | ```sh 14 | wasm-pack build glass-easel-template-compiler --target nodejs --out-dir pkg-nodejs 15 | ``` 16 | 17 | Build binary: 18 | 19 | ```sh 20 | cargo build --release 21 | ``` 22 | 23 | Build for simple browser usage: 24 | 25 | ```sh 26 | wasm-pack build glass-easel-template-compiler --target no-modules --out-dir pkg-web 27 | ``` 28 | 29 | See the main project for the detailed usage. 30 | -------------------------------------------------------------------------------- /glass-easel/guide/zh_CN/advanced/error_listener.md: -------------------------------------------------------------------------------- 1 | # 警告与错误 2 | 3 | # 错误监听器 4 | 5 | 在组件生命周期、事件回调中抛出的异常,会被 glass-easel 捕获。想要获取这些异常,可以注册一个错误监听器: 6 | 7 | ```js 8 | glassEasel.addGlobalErrorListener((err, { element }) => { 9 | err // 捕获的异常对象 10 | if element instanceof glassEasel.Comonent { 11 | element // 与这个异常相关的组件 12 | } 13 | // 返回 false 将取消 console 输出 14 | return false 15 | }) 16 | ``` 17 | 18 | 如果没有监听器或者监听器都没返回 `false` ,则错误信息会被输出到 console 中。如果 `glassEasel.globalOptions.throwGlobalError` 被设为 `true` ,则它会被再次抛出到全局。 19 | 20 | # 警告监听器 21 | 22 | glass-easel 也会产生一些警告用于提示一些常见的误用情况。默认情况下,警告会输出到 console 中。 23 | 24 | 类似于错误,警告也可以被监听到,例如: 25 | 26 | ```js 27 | glassEasel.addGlobalWarningListener((message) => { 28 | message // 警告信息 29 | // 返回 false 将取消 console 输出 30 | return false 31 | }) 32 | ``` 33 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/tests/base/env.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-new-func */ 2 | /* eslint-disable @typescript-eslint/no-implied-eval */ 3 | 4 | import type * as glassEasel from 'glass-easel' 5 | import { TmplGroup } from 'glass-easel-template-compiler' 6 | 7 | export const tmpl = (src: string): glassEasel.template.ComponentTemplate => { 8 | const group = new TmplGroup() 9 | group.addTmpl('', src) 10 | const genObjectSrc = `return ${group.getTmplGenObjectGroups()}` 11 | group.free() 12 | // console.info(genObjectSrc) 13 | const genObjectGroupList = new Function(genObjectSrc)() as { [key: string]: any } 14 | return { 15 | groupList: genObjectGroupList, 16 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 17 | content: genObjectGroupList['']!, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /glass-easel/guide/zh_CN/interaction/component_path.md: -------------------------------------------------------------------------------- 1 | # 组件路径 2 | 3 | 可以给组件起一个路径名称,用于给组件归类。 4 | 5 | 使用 Definition API 给组件命名的示例: 6 | 7 | ```js 8 | export const myComponent = componentSpace.defineComponent({ 9 | is: 'path/to/my/component', 10 | }) 11 | ``` 12 | 13 | 使用 Chaining API 给组件命名的示例: 14 | 15 | ```js 16 | export const myComponent = componentSpace.define('path/to/my/component') 17 | .registerComponent() 18 | ``` 19 | 20 | 在引用其他组件时,可以使用组件路径来指定,这对于含有递归引用的组件很实用: 21 | 22 | ```js 23 | componentSpace.defineComponent({ 24 | is: 'path/to/one/component', 25 | using: { 26 | // 使用相对路径来指定另一个组件 27 | another: '../another/component', 28 | }, 29 | }) 30 | componentSpace.defineComponent({ 31 | is: 'path/to/another/component', 32 | using: { 33 | // 使用绝对路径来指定另一个组件 34 | one: '/path/to/one/component', 35 | }, 36 | }) 37 | ``` 38 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/src/media_query.ts: -------------------------------------------------------------------------------- 1 | import type * as glassEasel from 'glass-easel' 2 | import { type GeneralComponent } from './component' 3 | 4 | export class MediaQueryObserver { 5 | private _$comp: GeneralComponent 6 | private _$observer: glassEasel.backend.Observer | null = null 7 | 8 | /** @internal */ 9 | constructor(comp: GeneralComponent) { 10 | this._$comp = comp 11 | } 12 | 13 | observe( 14 | descriptor: glassEasel.backend.MediaQueryStatus, 15 | listener: (status: { matches: boolean }) => void, 16 | ) { 17 | if (this._$observer) this._$observer.disconnect() 18 | this._$observer = 19 | this._$comp._$.getBackendContext()?.createMediaQueryObserver?.(descriptor, listener) || null 20 | } 21 | 22 | disconnect() { 23 | if (this._$observer) this._$observer.disconnect() 24 | this._$observer = null 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /glass-easel/src/external_shadow_tree.ts: -------------------------------------------------------------------------------- 1 | import { type Event, type ShadowedEvent } from './event' 2 | import { type GeneralBackendElement } from './backend' 3 | 4 | /** 5 | * An external shadow root 6 | * 7 | * It can be used to build an external component. 8 | * External component is a customizable subtree that can be composed with normal components. 9 | * It allows third-party frameworks to render a subtree and then compose it together. 10 | * However, the subtree must be created in the same backend context. 11 | */ 12 | export interface ExternalShadowRoot { 13 | root: GeneralBackendElement 14 | slot: GeneralBackendElement 15 | getIdMap(): { [id: string]: GeneralBackendElement } 16 | handleEvent(target: GeneralBackendElement, event: Event): void 17 | setListener( 18 | elem: GeneralBackendElement, 19 | ev: string, 20 | listener: (event: ShadowedEvent) => unknown, 21 | ): void 22 | } 23 | -------------------------------------------------------------------------------- /glass-easel-stylesheet-compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glass-easel-stylesheet-compiler", 3 | "description": "The stylesheet compiler of the glass-easel project.", 4 | "version": "0.17.2", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/wechat-miniprogram/glass-easel.git" 8 | }, 9 | "keywords": ["glass-easel"], 10 | "author": "wechat-miniprogram", 11 | "license": "MIT", 12 | "bugs": { 13 | "url": "https://github.com/wechat-miniprogram/glass-easel/issues" 14 | }, 15 | "homepage": "https://github.com/wechat-miniprogram/glass-easel", 16 | "files": [ 17 | "pkg-nodejs/glass_easel_stylesheet_compiler*", 18 | "/README.md" 19 | ], 20 | "main": "pkg-nodejs/glass_easel_stylesheet_compiler.js", 21 | "types": "pkg-nodejs/glass_easel_stylesheet_compiler.d.ts", 22 | "scripts": { 23 | "build": "wasm-pack build --target nodejs --out-dir pkg-nodejs" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strictNullChecks": true, 4 | "strictPropertyInitialization": true, 5 | "noUncheckedIndexedAccess": true, 6 | "useUnknownInCatchVariables": true, 7 | "noImplicitAny": true, 8 | "noImplicitOverride": true, 9 | "noImplicitReturns": true, 10 | "noImplicitThis": true, 11 | "strictFunctionTypes": true, 12 | "strictBindCallApply": true, 13 | "module": "es6", 14 | "target": "es6", 15 | "esModuleInterop": true, 16 | "moduleResolution": "node", 17 | "lib": ["ES6", "ES7", "DOM", "ESNext"], 18 | "types": ["jest", "node"], 19 | "declaration": false, 20 | "preserveConstEnums": true, 21 | "stripInternal": true 22 | }, 23 | "ts-node": { 24 | "compilerOptions": { 25 | "module": "CommonJS" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /glass-easel/guide/zh_CN/advanced/binding_map_update.md: -------------------------------------------------------------------------------- 1 | # 绑定映射表更新 2 | 3 | glass-easel 内置的模板引擎支持两种更新方式。 4 | 5 | * 虚拟树更新:更新时,遍历需要更新的 Shadow Tree ,并更新变化了的数据绑定; 6 | * 绑定映射表更新:更新时,根据改变的数据字段名、找到用到了该字段数据绑定表达式,然后更新它。 7 | 8 | 绑定映射表更新通常是一种更快速高效的更新方式,但它不能用于更新 `wx:if` `wx:for` 子节点树内部用到的数据字段。 9 | 10 | 每次更新时, glass-easel 会根据被设置的数据字段名,来选择应该使用哪种更新方式。 11 | 12 | 如果想要指定只其中一种更新方式,可以在编译模板时控制: 13 | 14 | ```js 15 | const compileTemplate = (src: string, updateMode = '') => { 16 | const group = new TmplGroup() 17 | group.addTmpl('', src) 18 | const genObjectSrc = `return ${group.getTmplGenObjectGroups()}` 19 | group.free() 20 | const genObjectGroupList = (new Function(genObjectSrc))() as { [key: string]: any } 21 | return { 22 | content: genObjectGroupList[''], 23 | updateMode, 24 | } 25 | } 26 | // 指定模板只使用虚拟树更新 27 | compileTemplate('
', 'virtualTree') 28 | // 指定模板只使用绑定映射表更新 29 | compileTemplate('
', 'bindingMap') 30 | ``` 31 | 32 | 注意:在不支持的模板上强行只使用绑定映射表更新,会导致出错或更新异常。 33 | -------------------------------------------------------------------------------- /glass-easel/guide/zh_CN/interaction/placeholder.md: -------------------------------------------------------------------------------- 1 | # 占位组件 2 | 3 | 有时,出于性能考虑,一些组件需要被延迟加载。此时,可以设置一个占位组件,当一个组件缺失时,可以用占位组件来暂时代替。等到组件被注册之后,占位组件会被自动替换成它。例如: 4 | 5 | ```js 6 | export const placeholderComponent = componentSpace.defineComponent({ 7 | template: compileTemplate(` 8 |
Loading...
9 | `), 10 | }) 11 | 12 | // 使用 Definition API 设置占位组件 13 | export const myComponent = componentSpace.defineComponent({ 14 | using: { 15 | child: 'lazy-components/child', 16 | placeholder: placeholderComponent, 17 | }, 18 | placeholders: { 19 | child: 'placeholder', 20 | }, 21 | }) 22 | // 或使用 Chaining API 设置占位组件 23 | export const myComponent = componentSpace.define() 24 | .usingComponents({ 25 | child: 'lazy-components/child', 26 | placeholder: placeholderComponent, 27 | }) 28 | .placeholders({ 29 | child: 'placeholder', 30 | }) 31 | .registerComponent() 32 | ``` 33 | 34 | 等到对应的被注册时,占位组件会被自动替换: 35 | 36 | ```js 37 | componentSpace.defineComponent({ 38 | is: 'lazy-components/child', 39 | }) 40 | ``` 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 wechat-miniprogram 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glass-easel-miniprogram-template", 3 | "version": "0.17.2", 4 | "main": "src/index.ts", 5 | "scripts": { 6 | "build": "webpack --config webpack.config.js", 7 | "dev": "webpack --config webpack.dev.config.js --watch" 8 | }, 9 | "dependencies": { 10 | "glass-easel": "workspace:*", 11 | "glass-easel-miniprogram-adapter": "workspace:*" 12 | }, 13 | "devDependencies": { 14 | "@typescript-eslint/eslint-plugin": "^6.21.0", 15 | "@typescript-eslint/parser": "^6.21.0", 16 | "css-loader": "^6.7.1", 17 | "eslint": "^7.32.0", 18 | "eslint-plugin-import": "^2.22.1", 19 | "eslint-plugin-promise": "^4.2.1", 20 | "glass-easel-miniprogram-typescript": "workspace:*", 21 | "glass-easel-miniprogram-webpack-plugin": "workspace:*", 22 | "less": "^4.1.3", 23 | "less-loader": "^11.0.0", 24 | "mini-css-extract-plugin": "^2.6.1", 25 | "ts-loader": "^9.4.2", 26 | "typescript": "~5.2.2", 27 | "webpack": "^5.101.3", 28 | "webpack-cli": "^6.0.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /glass-easel-stylesheet-compiler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "glass-easel-stylesheet-compiler" 3 | version = "0.17.2" 4 | authors = ["LastLeaf "] 5 | description = "The stylesheet compiler of the glass-easel project." 6 | license = "MIT" 7 | documentation = "https://github.com/wechat-miniprogram/glass-easel" 8 | repository = "https://github.com/wechat-miniprogram/glass-easel" 9 | homepage = "https://github.com/wechat-miniprogram/glass-easel" 10 | edition = "2021" 11 | 12 | [lib] 13 | crate-type = ["cdylib", "rlib"] 14 | 15 | [[bin]] 16 | name = "glass-easel-stylesheet-compiler" 17 | path = "src/main.rs" 18 | 19 | [features] 20 | default = ["js_bindings"] 21 | js_bindings = [] 22 | 23 | [dependencies] 24 | cssparser = "0.34" 25 | sourcemap = "6" 26 | serde = "1" 27 | serde_json = "1" 28 | serde-wasm-bindgen = "0.6" 29 | wasm-bindgen = "0.2" 30 | js-sys = "0.3" 31 | log = "0.4" 32 | console_log = "0.2" 33 | env_logger = "0.9" 34 | clap = { version = "4", features = ["derive"] } 35 | urlencoding = "2" 36 | 37 | [package.metadata.wasm-pack.profile.release] 38 | wasm-opt = false 39 | -------------------------------------------------------------------------------- /glass-easel/guide/zh_CN/advanced/build_args.md: -------------------------------------------------------------------------------- 1 | # 构建参数 2 | 3 | glass-easel 的构建脚本会根据 `GLASS_EASEL_ARGS` 环境变量来构建出不同的结果。 4 | 5 | 首先,构建模式会决定构建产物的文件名(位于 dist 目录下)以及不同的 [自定义后端](custom_backend.md) 支持度。目前支持的构建模式如下。 6 | 7 | | 构建模式 | 文件名 | 支持的自定义后端 | 产物使用方式 | 8 | | -------- | ------ | ---------------- | ------------ | 9 | | all | glass_easel.all | 支持全部后端(运行时自动选择) | CommonJS | 10 | | shadow | glass_easel.shadow | 支持 shadow 模式后端 | CommonJS | 11 | | shadow-global | glass_easel.shadow.global | 支持 shadow 模式后端 | 全局变量 | 12 | | composed | glass_easel.composed | 支持 composed 模式后端 | CommonJS | 13 | | composed-global | glass_easel.composed.global | 支持 composed 模式后端 | 全局变量 | 14 | | domlike | glass_easel.domlike | 支持 DOM 后端 | CommonJS | 15 | | domlike-global | glass_easel.domlike.global | 支持 DOM 后端 | 全局变量 | 16 | 17 | 一次可以同时启用多个构建模式。在 node.js 和打包工具中,第一个构建模式会视为被 import 时采用的构建结果。 18 | 19 | 额外参数可以修饰构建结果: 20 | 21 | * `--minimize` / `--no-minimize` 可以启用、禁用代码压缩混淆; 22 | * `--dev` 可以激活 development 构建模式。 23 | 24 | 例如,如果想要构建出支持全部后端和全局量模式 DOM 后端的两种构建结果、同时禁用代码压缩混淆,则 `GLASS_EASEL_ARGS` 环境变量应设为: 25 | 26 | ``` 27 | all domlike-global --no-minimize 28 | ``` 29 | -------------------------------------------------------------------------------- /glass-easel/guide/zh_CN/styling/external_class.md: -------------------------------------------------------------------------------- 1 | # 外部样式类 2 | 3 | 有时,一个组件的部分样式规则需要由它的使用者来指定。此时可以使用 **外部样式类** 。 4 | 5 | 组件可以指定它自身的一些 class 可以由组件外传递,例如: 6 | 7 | ```js 8 | // 使用 Definition API 指定外部样式类 9 | export const childComponent = componentSpace.defineComponent({ 10 | externalClasses: ['my-class'], 11 | // 在模板的 class 中可以使用外部样式类 12 | template: compileTemplate(` 13 |
14 | `), 15 | }) 16 | // 或使用 Chaining API 指定外部样式类 17 | export const childComponent = componentSpace.define() 18 | .externalClasses(['my-class']) 19 | .template(compileTemplate(` 20 |
21 | `)) 22 | .registerComponent() 23 | ``` 24 | 25 | 使用这个组件时,就可以指定: 26 | 27 | ```js 28 | export const myComponent = componentSpace.defineComponent({ 29 | using: { 30 | child: childComponent, 31 | }, 32 | template: compileTemplate(` 33 | 34 | `), 35 | }) 36 | ``` 37 | 38 | 这样,子组件中的 `
` 就会最终应用 `.some-class` 的样式规则: 39 | 40 | ```css 41 | .some-class { 42 | /* ... */ 43 | } 44 | ``` 45 | 46 | 即使启用了 [样式隔离](style_isolation.md) ,外部样式类依然可用。 47 | -------------------------------------------------------------------------------- /glass-easel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glass-easel", 3 | "description": "The core module of the glass-easel project", 4 | "version": "0.17.2", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/wechat-miniprogram/glass-easel.git" 8 | }, 9 | "keywords": ["glass-easel"], 10 | "author": "wechat-miniprogram", 11 | "license": "MIT", 12 | "bugs": { 13 | "url": "https://github.com/wechat-miniprogram/glass-easel/issues" 14 | }, 15 | "homepage": "https://github.com/wechat-miniprogram/glass-easel", 16 | "main": "dist/glass_easel.all.js", 17 | "module": "dist/glass_easel.all.es.js", 18 | "types": "dist/glass_easel.d.ts", 19 | "scripts": { 20 | "doc": "typedoc src/index.ts --excludePrivate --excludeProtected --excludeInternal", 21 | "build": "rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript", 22 | "dev": "GLASS_EASEL_ARGS=--dev npm run build", 23 | "lint": "eslint --ext .js,.ts src", 24 | "test": "jest -c jest.config.js", 25 | "coverage": "jest -c jest.config.js --collect-coverage" 26 | }, 27 | "devDependencies": { 28 | "glass-easel-template-compiler": "workspace:*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /glass-easel-template-compiler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "glass-easel-template-compiler" 3 | version = "0.17.2" 4 | authors = ["LastLeaf "] 5 | description = "The template compiler of the glass-easel project." 6 | license = "MIT" 7 | documentation = "https://github.com/wechat-miniprogram/glass-easel" 8 | repository = "https://github.com/wechat-miniprogram/glass-easel" 9 | homepage = "https://github.com/wechat-miniprogram/glass-easel" 10 | edition = "2018" 11 | 12 | [lib] 13 | crate-type = ["cdylib", "rlib", "staticlib"] 14 | 15 | [[bin]] 16 | name = "glass-easel-template-compiler" 17 | path = "src/main.rs" 18 | 19 | [features] 20 | default = ["js_bindings", "c_bindings"] 21 | js_bindings = [] 22 | c_bindings = ["cbindgen"] 23 | 24 | [dependencies] 25 | cssparser = "0.34" 26 | entities = "1" 27 | lazy_static = "1" 28 | regex = "^1.10.4" 29 | serde = "1" 30 | serde_json = "1" 31 | serde-wasm-bindgen = "0.6" 32 | wasm-bindgen = "0.2.79" 33 | js-sys = "0.3" 34 | log = "0.4" 35 | console_log = "0.2" 36 | env_logger = "0.9" 37 | clap = "2" 38 | cbindgen = { version = "0.21", optional = true } 39 | compact_str = "0.7" 40 | sourcemap = "7.0.1" 41 | 42 | [package.metadata.wasm-pack.profile.release] 43 | wasm-opt = false 44 | -------------------------------------------------------------------------------- /glass-easel-template-compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glass-easel-template-compiler", 3 | "description": "The template compiler of the glass-easel project.", 4 | "version": "0.17.2", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/wechat-miniprogram/glass-easel.git" 8 | }, 9 | "keywords": ["glass-easel"], 10 | "author": "wechat-miniprogram", 11 | "license": "MIT", 12 | "bugs": { 13 | "url": "https://github.com/wechat-miniprogram/glass-easel/issues" 14 | }, 15 | "homepage": "https://github.com/wechat-miniprogram/glass-easel", 16 | "files": [ 17 | "pkg/glass_easel_template_compiler*", 18 | "/main.js", 19 | "/module.js", 20 | "/README.md" 21 | ], 22 | "main": "main.js", 23 | "module": "module.js", 24 | "browser": "pkg/glass_easel_template_compiler.js", 25 | "types": "pkg/glass_easel_template_compiler.d.ts", 26 | "scripts": { 27 | "build": "wasm-pack build --target bundler && mv pkg/package.json pkg/package.json.orig && rollup -o pkg/glass_easel_template_compiler_bg.cjs.js -f cjs pkg/glass_easel_template_compiler_bg.js" 28 | }, 29 | "sideEffects": [ 30 | "pkg/glass_easel_template_compiler.js", 31 | "pkg/snippets/*" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-webpack-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glass-easel-miniprogram-webpack-plugin", 3 | "description": "The webpack plugin of the glass-easel project for MiniProgram file structure", 4 | "version": "0.17.2", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/wechat-miniprogram/glass-easel.git" 8 | }, 9 | "keywords": [ 10 | "glass-easel" 11 | ], 12 | "author": "wechat-miniprogram", 13 | "license": "MIT", 14 | "bugs": { 15 | "url": "https://github.com/wechat-miniprogram/glass-easel/issues" 16 | }, 17 | "homepage": "https://github.com/wechat-miniprogram/glass-easel", 18 | "main": "index.js", 19 | "scripts": { 20 | "build": "tsc -p .", 21 | "lint": "eslint src/**/*.ts" 22 | }, 23 | "peerDependencies": { 24 | "glass-easel": "workspace:*", 25 | "glass-easel-miniprogram-adapter": "workspace:*", 26 | "webpack": "^5.101.3" 27 | }, 28 | "dependencies": { 29 | "chalk": "4", 30 | "chokidar": "^4.0.3", 31 | "glass-easel-stylesheet-compiler": "workspace:*", 32 | "glass-easel-template-compiler": "workspace:*", 33 | "source-map": "^0.7.4", 34 | "webpack-sources": "^3.2.1", 35 | "webpack-virtual-modules": "^0.5.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glass-easel-miniprogram-typescript", 3 | "description": "A checker for the glass-easel project in MiniProgram file structure", 4 | "version": "0.17.2", 5 | "engines": { 6 | "node": ">=20.0.0" 7 | }, 8 | "bin": { 9 | "miniprogram-typescript-check": "dist/cli.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/wechat-miniprogram/glass-easel.git" 14 | }, 15 | "keywords": [ 16 | "glass-easel" 17 | ], 18 | "author": "wechat-miniprogram", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/wechat-miniprogram/glass-easel/issues" 22 | }, 23 | "homepage": "https://github.com/wechat-miniprogram/glass-easel", 24 | "main": "dist/index.js", 25 | "types": "src/index.ts", 26 | "scripts": { 27 | "build": "tsc -p .", 28 | "dev": "tsc -w -p .", 29 | "lint": "eslint src/**/*.ts", 30 | "start": "node dist/cli.js", 31 | "build-and-start": "npm run build && node dist/cli.js" 32 | }, 33 | "peerDependencies": { 34 | "typescript": "^5.2.2" 35 | }, 36 | "dependencies": { 37 | "chalk": "4", 38 | "chokidar": "^4.0.3", 39 | "glass-easel-template-compiler": "workspace:*" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /glass-easel-template-compiler/src/path.rs: -------------------------------------------------------------------------------- 1 | pub(crate) fn normalize(path: &str) -> String { 2 | let mut slices = vec![]; 3 | for slice in path.split('/') { 4 | match slice { 5 | "." => {} 6 | ".." => { 7 | slices.pop(); 8 | } 9 | _ => { 10 | slices.push(slice); 11 | } 12 | } 13 | } 14 | slices.join("/") 15 | } 16 | 17 | pub(crate) fn resolve(base: &str, rel: &str) -> String { 18 | let mut slices = vec![]; 19 | let main = if rel.starts_with('/') { 20 | &rel[1..] 21 | } else { 22 | for slice in base.split('/') { 23 | match slice { 24 | "." => {} 25 | ".." => { 26 | slices.pop(); 27 | } 28 | _ => { 29 | slices.push(slice); 30 | } 31 | } 32 | } 33 | rel 34 | }; 35 | slices.pop(); 36 | for slice in main.split('/') { 37 | match slice { 38 | "." => {} 39 | ".." => { 40 | slices.pop(); 41 | } 42 | _ => { 43 | slices.push(slice); 44 | } 45 | } 46 | } 47 | slices.join("/") 48 | } 49 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-adapter/README.md: -------------------------------------------------------------------------------- 1 | # glass-easel-miniprogram-adapter 2 | 3 | An MiniProgram interface adapter for glass-easel, which exports a mini-program-like API, such as `Component` and `Behavior` . 4 | 5 | Refer to the [glass-easel](https://github.com/wechat-miniprogram/glass-easel) project for further details. 6 | 7 | ## Build 8 | 9 | `nodejs` toolchain should be globally installed. 10 | 11 | Install dependencies: 12 | 13 | ```sh 14 | npm install 15 | ``` 16 | 17 | Build: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | Build Doc: 24 | 25 | ```sh 26 | npm run doc 27 | ``` 28 | 29 | Test: 30 | 31 | ```sh 32 | npm test 33 | ``` 34 | 35 | Test coverage: 36 | 37 | ```sh 38 | npm run coverage 39 | ``` 40 | 41 | ## Limitations 42 | 43 | Supported component API is a subset of mini-program API. See `docs` and mini-program docs for details. 44 | 45 | Style isolation support is also limited. 46 | 47 | * The `component: true` in JSON files should only be used in components, not pages (this influences the default style isolation settings). 48 | * The `styleIsolation` options should be specified in JSON files, not JS `Component` options. 49 | * Please work with [glass-easel-miniprogram-webpack-plugin](../glass-easel-miniprogram-webpack-plugin/) so that WXSS content can be correctly handled. 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "init-dev": "pnpm i && npm run build", 4 | "build": "pnpm -r run build" 5 | }, 6 | "devDependencies": { 7 | "@rollup/plugin-node-resolve": "^15.2.1", 8 | "@rollup/plugin-replace": "^5.0.2", 9 | "@rollup/plugin-terser": "^0.4.3", 10 | "@rollup/plugin-typescript": "^11.1.3", 11 | "@tsd/typescript": "^5.2.2", 12 | "@types/jest": "^26.0.24", 13 | "@types/node": "^20.19.11", 14 | "@typescript-eslint/eslint-plugin": "^6.21.0", 15 | "@typescript-eslint/parser": "^6.21.0", 16 | "eslint": "^7.32.0", 17 | "eslint-config-airbnb-base": "^14.2.1", 18 | "eslint-config-prettier": "^8.6.0", 19 | "eslint-plugin-import": "^2.22.1", 20 | "eslint-plugin-prettier": "^4.2.1", 21 | "eslint-plugin-promise": "^4.2.1", 22 | "jest": "^29.6.4", 23 | "jest-environment-jsdom": "^29.6.4", 24 | "jest-runner-tsd": "^6.0.0", 25 | "prettier": "^2.8.3", 26 | "rollup": "^3.29.1", 27 | "rollup-plugin-dts": "^6.0.2", 28 | "ts-jest": "^29.1.1", 29 | "ts-loader": "^9.4.4", 30 | "tsd-lite": "^0.8.0", 31 | "tslib": "^2.6.2", 32 | "typedoc": "^0.25.13", 33 | "typescript": "~5.2.2", 34 | "webpack": "^5.101.3", 35 | "webpack-cli": "^6.0.1", 36 | "webpack-sources": "^3.2.3" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /glass-easel-miniprogram-typescript/README.md: -------------------------------------------------------------------------------- 1 | # glass-easel-miniprogram-typescript 2 | 3 | An extra TypeScript checker for mini-program code running in glass-easel. 4 | 5 | Refer to the [glass-easel](https://github.com/wechat-miniprogram/glass-easel) project for further details. 6 | 7 | ## Features 8 | 9 | If the component is written in TypeScript, this tool can do some type-checking on expressions inside WXML. 10 | 11 | Firstly, the component `.ts` must export the component as default. For example: 12 | 13 | ```ts 14 | export default Component({ 15 | data: { 16 | hello: 'world', 17 | }, 18 | }) 19 | ``` 20 | 21 | Then in `.wxml` : 22 | 23 | ```xml 24 |
{{ hello }}
25 | 26 | 27 |
{{ heloo }}
28 | ``` 29 | 30 | This tool is based on TypeScript (a.k.a. `tsserver` ) for type-checking. 31 | 32 | Note that it only report errors in component WXML files. For type errors in TS files, you should run standard TypeScript commands. 33 | 34 | ## Usage 35 | 36 | After install this module, the `miniprogram-typescript-check` tool should be available. 37 | 38 | See all options: `npx miniprogram-typescript-check --help` 39 | 40 | In most cases, this command is suggested: `npx miniprogram-typescript-check -p [PATH_TO_SRC]` 41 | -------------------------------------------------------------------------------- /glass-easel/guide/zh_CN/styling/style_isolation.md: -------------------------------------------------------------------------------- 1 | # 样式隔离 2 | 3 | glass-easel 的默认设置中,组件之间的样式是共享的。如果想将一个样式表仅用于一个组件,可以考虑启用 style scope 支持。 4 | 5 | 在 DOM 环境下, style scope 要求样式表预处理时对样式表中的 class 都添加一个前缀,例如: 6 | 7 | ```css 8 | .my-prefix--header { 9 | font-size: 1.5em; 10 | } 11 | .my-prefix--footer { 12 | font-size: 0.9em; 13 | } 14 | ``` 15 | 16 | 通过 `glass-easel-stylesheet-compiler` 工具可以为样式表添加固定的前缀,具体用法请参考它的相关文档。 17 | 18 | 添加前缀后,可以注册一个 style scope : 19 | 20 | ```js 21 | const myStyleScope = componentSpace.styleScopeManager.register('my-prefix') 22 | ``` 23 | 24 | 组件定义时,可以指定它使用这个 style scope : 25 | 26 | ```js 27 | export const myComponent = componentSpace.defineComponent({ 28 | options: { 29 | styleScope: myStyleScope, 30 | }, 31 | template: compileTemplate(` 32 |
33 |