` 但你也可以传入一个字符串来定制它 (比如: 'span', 'li' 等.)
64 | - `id` : 在基础包裹元素上添加id属性, 默认是`svelte-wrapper`.
65 | - `className` : 在基础包裹元素上添加class属性,允许你在样式文件定义实现.
66 | - `styles` : 在基础包裹元素上添加内联样式属性, 可以覆盖`className`中的样式定义.
67 |
68 | # 示例
69 |
70 | 在下面的例子中, 我们要使用的[svelte component](https://github.com/FE-PIRL/svere/blob/master/examples/src/Component.svelte) 是一个接受prop后渲染, 通过点击触发事件的简单组件.
71 | 将它打包成`umd`格式的单文件, 以便于可以被其它框架方便地引入.
72 |
73 | ```sveltehtml
74 |
89 |
90 |
91 | Hello {name}, welcome!
92 |
93 | add count: {count}
94 |
95 |
96 | update name: {name}
97 |
98 |
99 |
100 |
115 | ```
116 |
117 | ## React
118 |
119 | ```jsx
120 | import React, { useState } from "react";
121 | import SvelteComponent from "./svelte-component";
122 | import toReact from '@svere/core/dist/react.js'
123 |
124 | const wrapperProps = {
125 | element: "section",
126 | className: "section-css",
127 | id: "svelte-react",
128 | styles: {
129 | border: "1px solid gray",
130 | },
131 | };
132 | const ReactComponent = toReact(SvelteComponent, wrapperProps);
133 |
134 | const App = () => {
135 | const [name, setName] = useState('ben');
136 | const changeName = () => setName(n => {
137 | return name === 'ben' ? 'yasin' : 'ben'
138 | });
139 |
140 | const handleEventCallback = (e) => {
141 | console.log(e.detail)
142 | };
143 |
144 | const handleWatchCallback = (name) => {
145 | console.log(name)
146 | };
147 |
148 | return (
149 |
150 |
155 |
156 |
157 |
158 | change inner variable name
159 |
160 | );
161 | };
162 | ```
163 |
164 | ## Vue2
165 |
166 | ```vue
167 |
168 |
169 |
174 | change inner variable name
175 |
176 |
177 |
178 |
204 | ```
205 |
206 | ## Vue3
207 |
208 | ```vue
209 |
210 |
215 |
216 | change inner variable name
217 |
218 |
219 |
256 |
257 |
262 | ```
263 |
264 | # 命令行
265 | 使用我们的[CLI](https://github.com/FE-PIRL/svere/tree/master/packages/cli) 在本地尝试svere.
266 |
267 | 使用 [npm](https://www.npmjs.com/):
268 |
269 | ```bash
270 | npm install @svere/core
271 | ```
272 |
273 | 或 [yarn](https://yarnpkg.com/lang/en/):
274 |
275 | ```bash
276 | yarn add @svere/core
277 | ```
278 |
279 | # 待办
280 |
281 | - 添加更多特性到core中, 例如: 子组件、插槽.
--------------------------------------------------------------------------------
/packages/cli/src/commands/create.ts:
--------------------------------------------------------------------------------
1 | import ora from "ora";
2 | import path from "path";
3 | import execa from "execa";
4 | import fs from "fs-extra";
5 | import degit from "degit";
6 | import * as colors from "kleur/colors";
7 | import { logger } from "../helpers/logger";
8 | import { appName } from "../constants";
9 | import { LoggerOptions, PackageJson } from "../types";
10 | const pkg: PackageJson = require(path.join(__dirname, "../../package.json"));
11 | //TODO fetch from remote github
12 | const templates = ["default"];
13 |
14 | export async function command(commandOptions: any) {
15 | const force = commandOptions.force;
16 | const cache = commandOptions.cache;
17 | const debug = commandOptions.debug;
18 | const template = commandOptions.template;
19 | if (debug) {
20 | logger.level = "debug";
21 | }
22 |
23 | const targetDir = path.join(
24 | process.cwd(),
25 | commandOptions.targetDir || `svere-${template.replace("/", "-")}`
26 | );
27 | if (!templates.includes(template)) {
28 | logger.error(
29 | `invalid template ${template}. Valid: ${colors.green(
30 | JSON.stringify(templates)
31 | )}`
32 | );
33 | return;
34 | }
35 |
36 | await installTemplate(targetDir, template, force, cache, debug);
37 | await updatePackage(targetDir);
38 |
39 | if (!commandOptions.skipGit) {
40 | await gitInit(targetDir);
41 | if (!commandOptions.skipCommit) {
42 | await gitCommit(targetDir);
43 | }
44 | }
45 |
46 | if (!commandOptions.skipInstall) {
47 | await installDependencies(targetDir, commandOptions.packageManager);
48 | }
49 |
50 | await quickStart(
51 | targetDir,
52 | commandOptions.packageManager,
53 | !commandOptions.skipInstall
54 | );
55 | }
56 |
57 | async function installTemplate(targetDir, template, force, cache, debug) {
58 | const cloneSpinner = ora({
59 | text: `Creating ${colors.cyan(targetDir)} from template ...\n`,
60 | prefixText: `[${appName}]`
61 | });
62 | try {
63 | cloneSpinner.start();
64 | const empty =
65 | !fs.existsSync(targetDir) || !fs.readdirSync(targetDir).length;
66 | if (!empty) {
67 | if (!force) {
68 | throw Error(
69 | `Directory ${colors.cyan(
70 | targetDir
71 | )} not empty, use -f or --force to overwrite it`
72 | );
73 | }
74 | }
75 | await fs.emptyDir(targetDir);
76 |
77 | const githubRepo = pkg.repository.templates.match(
78 | /github\.com\/(.*).git/
79 | )[1];
80 | const beta = pkg.version.indexOf("beta") > -1;
81 | const degitPath = `${githubRepo}/${template}${beta ? "#beta" : ""}`;
82 | const degitOptions = {
83 | cache,
84 | force,
85 | verbose: debug,
86 | mode: "tar"
87 | };
88 | if (debug) {
89 | logger.debug(
90 | `degit ${colors.cyan(degitPath)}`,
91 | degitOptions as LoggerOptions
92 | );
93 | }
94 | const emitter = degit(degitPath, degitOptions);
95 |
96 | emitter.on("info", info => {
97 | logger.info(info.message);
98 | });
99 | emitter.on("warn", warning => {
100 | logger.warn(warning.message);
101 | });
102 | emitter.on("error", error => {
103 | logger.error(error.message, error);
104 | throw Error(error.message);
105 | });
106 |
107 | await emitter.clone(targetDir);
108 | cloneSpinner.succeed(`Created ${colors.cyan(targetDir)} successfully`);
109 | } catch (error) {
110 | cloneSpinner.fail(`Failed to create ${colors.cyan(targetDir)}`);
111 | logger.error(error.message);
112 | process.exit(1);
113 | }
114 | }
115 |
116 | async function updatePackage(dir) {
117 | const pkgFile = path.join(dir, "package.json");
118 | const pkg = require(pkgFile);
119 | pkg.name = path.basename(dir);
120 | fs.writeFileSync(pkgFile, JSON.stringify(pkg, null, 2));
121 | }
122 |
123 | function _installProcess(packageManager, npmInstallOptions) {
124 | switch (packageManager) {
125 | case "npm":
126 | return execa(
127 | "npm",
128 | ["install", "--loglevel", "error"],
129 | npmInstallOptions
130 | );
131 | case "yarn":
132 | return execa("yarn", ["--silent"], npmInstallOptions);
133 | case "pnpm":
134 | return execa("pnpm", ["install", "--reporter=silent"], npmInstallOptions);
135 | default:
136 | throw new Error("Unspecified package installer.");
137 | }
138 | }
139 |
140 | async function installDependencies(dir, packageManager) {
141 | const installSpinner = ora({
142 | text: `Installing dependencies, this might take a while ...\n`,
143 | prefixText: `[${appName}]`
144 | });
145 | try {
146 | installSpinner.start();
147 | const npmInstallOptions = {
148 | cwd: dir,
149 | stdio: "inherit"
150 | } as any;
151 |
152 | const npmInstallProcess = _installProcess(
153 | packageManager,
154 | npmInstallOptions
155 | );
156 | npmInstallProcess.stdout && npmInstallProcess.stdout.pipe(process.stdout);
157 | npmInstallProcess.stderr && npmInstallProcess.stderr.pipe(process.stderr);
158 | await npmInstallProcess;
159 |
160 | installSpinner.succeed("Installed dependencies");
161 | } catch (error) {
162 | installSpinner.fail("Failed to install dependencies");
163 | logger.error(error.message);
164 | process.exit(1);
165 | }
166 | }
167 |
168 | async function gitInit(dir) {
169 | const gitInitSpinner = ora({
170 | text: `Initialing git repo ...\n`,
171 | prefixText: `[${appName}]`
172 | });
173 | try {
174 | gitInitSpinner.start();
175 | await execa("git", ["init"], { cwd: dir });
176 | gitInitSpinner.succeed("Initialized git repo");
177 | } catch (error) {
178 | gitInitSpinner.fail("Failed to initialize git repo");
179 | logger.error(`Failed to initialize git in ${dir}` + error.message);
180 | process.exit(1);
181 | }
182 | }
183 |
184 | async function gitCommit(dir) {
185 | const gitCommitSpinner = ora({
186 | text: `Committing git ...\n`,
187 | prefixText: `[${appName}]`
188 | });
189 | try {
190 | gitCommitSpinner.start();
191 | await execa("git", ["add", "."], { cwd: dir });
192 | await execa("git", ["commit", "-m initial commit"], { cwd: dir });
193 | gitCommitSpinner.succeed("Completed initial commit");
194 | } catch (error) {
195 | gitCommitSpinner.fail("Failed to commit git");
196 | logger.error(`Failed to commit git in ${dir}` + error.message);
197 | process.exit(1);
198 | }
199 | }
200 |
201 | async function quickStart(dir, pm, installed) {
202 | function _formatCommand(command, description) {
203 | return " " + command.padEnd(17) + colors.dim(description);
204 | }
205 |
206 | console.log(``);
207 | console.log(colors.bold(colors.underline(`Quickstart:`)));
208 | console.log(``);
209 | console.log(` cd ${dir}`);
210 | console.log(` ${pm} start`);
211 | console.log(``);
212 | console.log(colors.bold(colors.underline(`All Commands:`)));
213 | console.log(``);
214 | console.log(
215 | _formatCommand(
216 | `${pm} install`,
217 | `Install your dependencies. ${
218 | installed
219 | ? "(We already ran this one for you!)"
220 | : "(You asked us to skip this step!)"
221 | }`
222 | )
223 | );
224 | console.log(_formatCommand(`${pm} start`, "Start development server."));
225 | console.log(_formatCommand(`${pm} run build`, "Build your component."));
226 | console.log(
227 | _formatCommand(`${pm} run lint`, "Check code quality and formatting.")
228 | );
229 | console.log(_formatCommand(`${pm} run test`, "Run your tests."));
230 | console.log(_formatCommand(`${pm} run doc`, "Run storybook for component."));
231 | console.log(``);
232 | }
233 |
--------------------------------------------------------------------------------
/packages/cli/README_ZH.md:
--------------------------------------------------------------------------------
1 | # SVERE CLI
2 |
3 | 为svere配套的脚手架.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | [English](https://github.com/FE-PIRL/svere/blob/master/packages/cli/README.md) | 简体中文
13 |
14 | ---
15 |
16 | - [介绍](#intro)
17 | - [特性](#features)
18 | - [安装](#install)
19 | - [快速开始](#quick-start)
20 | - [定制化](#customization)
21 | - [发布](#publishing)
22 | - [API参考](#api-reference)
23 | - [作者](#author)
24 | - [协议](#license)
25 |
26 | # 介绍
27 |
28 | 尽管你可以自己搭建一个工程来生产满足要求的目标文件,但你仍然会有大量的工作要做。我们的目的是帮你处理掉这些繁琐的工作,让你专心于业务组件的开发。`Svere cli`是一个零配置的脚手架,涉及到组件的`开发`,`打包`,`语法检查`、`测试`、`文档编写`、`发布`的生命周期,使你有一个轻松的组件开发体验.
29 |
30 | # 特性
31 |
32 | * 实时Reload与Watch模式
33 | * 使用Typescript书写
34 | * 通过`svere test`执行crypress与Jest
35 | * 通过`svere lint`执行Eslint、Stylelint与Prettier
36 | * 通过`svere doc`驱动Storybook
37 | * 通过`svere.config.js`以及[code-specification-unid](https://github.com/FE-PIRL/code-specification-unid)的导出文件来定制化
38 |
39 | # 安装
40 |
41 | 使用 [npm](https://www.npmjs.com/):
42 |
43 | ```bash
44 | npm install -g @svere/cli
45 | ```
46 |
47 | 或者使用 [yarn](https://yarnpkg.com/lang/en/):
48 |
49 | ```bash
50 | yarn add global @svere/cli
51 | ```
52 |
53 | # 快速安装
54 |
55 | ```bash
56 | svere create mycom
57 | cd mycom
58 | yarn start
59 | ```
60 |
61 | 就是这样,您不需要担心TypeScript、Rollup、Jest或其他工具的配置. 只要开始编辑`src/components/MyComponent.svelte`就可以了!
62 |
63 | 下面是您可能会发现有用的命令列表:
64 |
65 | ```npm start``` or ```yarn start```
66 |
67 | 以开发/监视模式运行项目。您的项目将在更改后重新加载
68 |
69 | ```npm run build``` or ```yarn build```
70 |
71 | 使用Rollup, 将包输出到dist文件夹, 经过优化后打成多种格式(UMD和ES模块).
72 |
73 | ```npm test``` or ```yarn test```
74 |
75 | 本模板使用了 [Cypress](https://www.cypress.io/) 与 [testing-library](https://testing-library.com/docs/cypress-testing-library/intro/) 用来测试.
76 |
77 | 如果您打算测试您的组件,强烈建议您阅读他们的文档. 您可以通过运行`svere test-co`来见证一个简单的示例.
78 |
79 | ```npm run lint``` or ```yarn lint```
80 |
81 | 本模板整合了 [code-specification-unid](https://github.com/FE-PIRL/code-specification-unid) 用来作质量检查.
82 |
83 | 如果您打算检查您的组件,强烈建议您阅读他们的文档.
84 |
85 | 默认的不带选项的命令将会驱动Eslint和Stylelint与Prettier一起工作.
86 |
87 | ```npm run doc``` or ```yarn doc```
88 |
89 | 本模板整合了 [Storybook](https://storybook.js.org/) 用来作文档编写.
90 |
91 | 你可以使用命令`svere doc -b`来生成静态文档.
92 |
93 |
94 | # 定制化
95 |
96 | ### Rollup
97 |
98 | > **❗⚠️❗ 警告 **:
99 | > 这些修改将覆盖SVERE的默认行为和配置, 因为它们可以使内部保证和假设失效。这些类型的更改会破坏内部行为,并且对更新非常脆弱。谨慎使用!
100 | SVERE使用了Rollup作为打包工具. 大多数的默认配置都是固定的. 但是,如果您确实希望更改rollup的配置, 可以在项目的根目录下创建一个名为`svere.config.js`的文件,如下所示:
101 |
102 | ```js
103 | // Not transpiled with TypeScript or Babel, so use plain Es6/Node.js!
104 | module.exports = {
105 | // This function will run for each entry/format/env combination
106 | rollup(config, options) {
107 | return config; // always return a config.
108 | },
109 | };
110 | ```
111 |
112 | 对象 `options` 包含了以下属性:
113 |
114 | ```tsx
115 | export interface SvereOptions {
116 | // Name of package
117 | name: string;
118 | // Port for dev
119 | port: number;
120 | // path to file
121 | input: string;
122 | // never launch browser automatically
123 | silent: boolean;
124 | // Module format
125 | format: 'umd' | 'esm' | 'iife';
126 | // Environment
127 | env: 'development' | 'production';
128 | // Path to tsconfig file
129 | tsconfig?: string;
130 | // Is error extraction running?
131 | extractErrors?: boolean;
132 | // Is minifying?
133 | minify?: boolean;
134 | // Is this the very first rollup config (and thus should one-off metadata be extracted)?
135 | writeMeta?: boolean;
136 | // Only transpile, do not type check (makes compilation faster)
137 | transpileOnly?: boolean;
138 | }
139 | ```
140 |
141 | #### 示例: 添加Postcss插件
142 |
143 | ```js
144 | const postcss = require('rollup-plugin-postcss');
145 | const autoprefixer = require('autoprefixer');
146 | const cssnano = require('cssnano');
147 |
148 | module.exports = {
149 | rollup(config, options) {
150 | config.plugins.push(
151 | postcss({
152 | plugins: [
153 | autoprefixer(),
154 | cssnano({
155 | preset: 'default',
156 | }),
157 | ],
158 | inject: false,
159 | // only write out CSS for the first bundle (avoids pointless extra files):
160 | extract: !!options.writeMeta,
161 | })
162 | );
163 | return config;
164 | },
165 | };
166 | ```
167 |
168 |
169 | # 发布
170 |
171 |
172 | # API参考
173 |
174 | ### ```svere start```
175 |
176 | ```bash
177 | Usage: svere start [options]
178 |
179 | start development server
180 |
181 | Options:
182 | --entry
specify entry file for dev (default: "src/main.ts")
183 | -d, --debug more debug logging (default: false)
184 | -s, --silent never launch the browser (default: false)
185 | -p, --port specify port for dev (default: "5000")
186 | -h, --help display help for command
187 | ```
188 |
189 |
190 | ### ```svere build```
191 |
192 | ```bash
193 | Usage: svere build [options]
194 |
195 | Build your component once and exit
196 |
197 | Options:
198 | --entry specify entry file for build (default: "src/components/index.ts")
199 | --fileName specify fileName exposed in UMD builds
200 | --format specify module format(s) (default: "umd,esm")
201 | --transpileOnly skip type checking (default: true)
202 | -d, --debug more debug logging (default: false)
203 | -bsb, --buildStorybook build storybook to static files (default: false)
204 | -h, --help display help for command
205 | ```
206 |
207 |
208 | ### ```svere test```
209 |
210 | ```bash
211 | Usage: svere test [options]
212 |
213 | Run cypress and jest test runner
214 |
215 | Options:
216 | -co, --cypressOpen run cypress open (default: false)
217 | -p, --port specify port for test (default: "5000")
218 | -h, --help display help for command
219 | ```
220 |
221 |
222 | ### ```svere lint```
223 |
224 | ```bash
225 | Usage: svere lint [options]
226 |
227 | Run eslint and stylelint with prettier
228 |
229 | Options:
230 | -js, --js run eslint with prettier only (default: false)
231 | -css, --css run stylelint with prettier only (default: false)
232 | -f, --format run prettier only (default: false)
233 | -jfs, --jsFiles specify files for eslint (default: "src/**/*.{js,jsx,ts,tsx,svelte}")
234 | -cfs, --cssFiles specify files for stylelint (default: "src/**/*.{less,postcss,css,scss,svelte}")
235 | -ffs, --formatFiles specify files for prettier (default: "src/**/*.{js,json,ts,tsx,svelte,css,less,scss,html,md}")
236 | -h, --help display help for command
237 | ```
238 |
239 |
240 | ### ```svere doc```
241 |
242 | ```bash
243 | Usage: svere doc [options]
244 |
245 | Start storybook for component
246 |
247 | Options:
248 | -p, --port specify port to run storybook (default: "6006")
249 | -b, --build build storybook to static files (default: false)
250 | -h, --help display help for command
251 | ```
252 |
253 | # 作者
254 |
255 | [benyasin](https://github.com/benyasin)
256 |
257 | # 协议
258 |
259 | [MIT](https://oss.ninja/mit/jaredpalmer/)
260 |
261 |
262 | # 待办
263 |
264 | * 添加一个命令来发布组件到npm或cdn上
265 |
266 |
--------------------------------------------------------------------------------
/packages/cli/src/helpers/createRollupConfig.ts:
--------------------------------------------------------------------------------
1 | import { safeVariableName, safePackageName, external } from "./utils";
2 | import { paths } from "../constants";
3 | import { RollupOptions } from "rollup";
4 | import { terser } from "rollup-plugin-terser";
5 | import commonjs from "@rollup/plugin-commonjs";
6 | import json from "@rollup/plugin-json";
7 | import replace from "@rollup/plugin-replace";
8 | import resolve, {
9 | DEFAULTS as RESOLVE_DEFAULTS
10 | } from "@rollup/plugin-node-resolve";
11 | import sourceMaps from "rollup-plugin-sourcemaps";
12 | import typescript from "rollup-plugin-typescript2";
13 | import ts from "typescript";
14 | import { SvereOptions } from "../types";
15 | import svelte from "rollup-plugin-svelte";
16 | import { scss } from "svelte-preprocess";
17 | import livereload from "rollup-plugin-livereload";
18 | import css from "rollup-plugin-css-only";
19 | import { spawn } from "child_process";
20 |
21 | export async function createRollupConfig(
22 | opts: SvereOptions,
23 | outputNum: number
24 | ): Promise {
25 | const shouldMinify =
26 | opts.minify !== undefined ? opts.minify : opts.env === "production";
27 |
28 | const outputName =
29 | opts.commandName === "start"
30 | ? "public/bundle.js"
31 | : [
32 | `${paths.appDist}/${safePackageName(opts.name)}`,
33 | opts.format,
34 | opts.env,
35 | shouldMinify ? "min" : "",
36 | "js"
37 | ]
38 | .filter(Boolean)
39 | .join(".");
40 |
41 | const tsconfigPath = opts.tsconfig || paths.tsconfigJson;
42 | // borrowed from https://github.com/facebook/create-react-app/pull/7248
43 | const tsconfigJSON = ts.readConfigFile(tsconfigPath, ts.sys.readFile).config;
44 | // borrowed from https://github.com/ezolenko/rollup-plugin-typescript2/blob/42173460541b0c444326bf14f2c8c27269c4cb11/src/parse-tsconfig.ts#L48
45 | const tsCompilerOptions = ts.parseJsonConfigFileContent(
46 | tsconfigJSON,
47 | ts.sys,
48 | "./"
49 | ).options;
50 |
51 | const serve = () => {
52 | let server;
53 |
54 | function toExit() {
55 | if (server) server.kill(0);
56 | }
57 |
58 | return {
59 | async writeBundle() {
60 | if (server) return;
61 | server = spawn(
62 | "npx",
63 | ["sirv public", "--host", "--dev", "--port", `${opts.port}`],
64 | {
65 | stdio: ["ignore", "inherit", "inherit"],
66 | shell: true
67 | }
68 | );
69 | if (!opts.silent) {
70 | setTimeout(() => {
71 | spawn("open", [`http://0.0.0.0:${opts.port}`], {
72 | stdio: ["ignore", "inherit", "inherit"],
73 | shell: true
74 | });
75 | }, 500);
76 | }
77 | process.on("SIGTERM", toExit);
78 | process.on("exit", toExit);
79 | }
80 | };
81 | };
82 |
83 | const plugins = [].concat(
84 | opts.commandName === "start"
85 | ? [
86 | svelte({
87 | compilerOptions: {
88 | dev: true
89 | },
90 | preprocess: [
91 | scss({
92 | /** options */
93 | })
94 | ]
95 | }),
96 | // we'll extract any component CSS out into
97 | // a separate file - better for performance
98 | css({ output: "bundle.css" }),
99 |
100 | // If you have external dependencies installed from
101 | // npm, you'll most likely need these plugins. In
102 | // some cases you'll need additional configuration -
103 | // consult the documentation for details:
104 | // https://github.com/rollup/plugins/tree/master/packages/commonjs
105 | resolve({
106 | browser: true,
107 | dedupe: ["svelte"]
108 | }),
109 | commonjs(),
110 | serve(),
111 | livereload("public")
112 | ]
113 | : [
114 | svelte({
115 | preprocess: [
116 | scss({
117 | /** options */
118 | })
119 | ],
120 | emitCss: false
121 | }),
122 | resolve({
123 | mainFields: [
124 | "module",
125 | "main",
126 | opts.target !== "node" ? "browser" : undefined
127 | ].filter(Boolean) as string[],
128 | extensions: [...RESOLVE_DEFAULTS.extensions, ".svelte"]
129 | }),
130 | // all bundled external modules need to be converted from CJS to ESM
131 | commonjs({
132 | // use a regex to make sure to include eventual hoisted packages
133 | include:
134 | opts.format === "umd"
135 | ? /\/node_modules\//
136 | : /\/regenerator-runtime\//
137 | }),
138 | json(),
139 | typescript({
140 | typescript: ts,
141 | tsconfig: opts.tsconfig,
142 | tsconfigDefaults: {
143 | exclude: [
144 | // all TS test files, regardless whether co-located or in test/ etc
145 | "**/*.spec.ts",
146 | "**/*.test.ts",
147 | "**/*.spec.tsx",
148 | "**/*.test.tsx",
149 | // TS defaults below
150 | "node_modules",
151 | "bower_components",
152 | "jspm_packages",
153 | paths.appDist
154 | ],
155 | compilerOptions: {
156 | sourceMap: true,
157 | declaration: true,
158 | jsx: "react"
159 | }
160 | },
161 | tsconfigOverride: {
162 | compilerOptions: {
163 | // TS -> esnext, then leave the rest to babel-preset-env
164 | target: "esnext",
165 | // don't output declarations more than once
166 | ...(outputNum > 0
167 | ? { declaration: false, declarationMap: false }
168 | : {})
169 | }
170 | },
171 | check: !opts.transpileOnly && outputNum === 0,
172 | useTsconfigDeclarationDir: Boolean(
173 | tsCompilerOptions?.declarationDir
174 | )
175 | }),
176 | opts.env !== undefined &&
177 | replace({
178 | preventAssignment: true,
179 | "process.env.NODE_ENV": JSON.stringify(opts.env)
180 | }),
181 | sourceMaps(),
182 | shouldMinify &&
183 | terser({
184 | output: { comments: false },
185 | compress: {
186 | keep_infinity: true,
187 | pure_getters: true,
188 | passes: 10
189 | },
190 | ecma: 5,
191 | toplevel: opts.format === "umd"
192 | })
193 | ]
194 | );
195 |
196 | return {
197 | external: ["svelte"],
198 | // Tell Rollup the entry point to the package
199 | input: opts.input,
200 | // Rollup has treeshaking by default, but we can optimize it further...
201 | treeshake: {
202 | propertyReadSideEffects: false
203 | },
204 | // Establish Rollup output
205 | output: {
206 | // Set filenames of the consumer's package
207 | file: outputName,
208 | // Pass through the file format
209 | format: opts.format,
210 | // Do not let Rollup call Object.freeze() on namespace import objects
211 | // (i.e. import * as namespaceImportObject from...) that are accessed dynamically.
212 | freeze: false,
213 | // Respect tsconfig esModuleInterop when setting __esModule.
214 | esModule: Boolean(tsCompilerOptions?.esModuleInterop),
215 | name: opts.name || safeVariableName(opts.name),
216 | sourcemap: opts.commandName !== "start",
217 | exports: "named"
218 | },
219 | plugins,
220 | watch: {
221 | clearScreen: true
222 | }
223 | };
224 | }
225 |
--------------------------------------------------------------------------------
/packages/core/README.md:
--------------------------------------------------------------------------------
1 | # SVERE CORE
2 |
3 | Adapters for svere core.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | English | [简体中文](https://github.com/FE-PIRL/svere/blob/master/packages/core/README_ZH.md)
13 |
14 | ---
15 |
16 | - [Intro](#intro)
17 | - [Install](#install)
18 | - [Usage](#usage)
19 | - [Examples](#examples)
20 | - [React](#react)
21 | - [Vue2](#vue2)
22 | - [Vue3](#vue3)
23 | - [Cli](#cli)
24 | - [Todos](#todos)
25 |
26 | # Intro
27 |
28 | Managing support for libraries that provide UI components across frameworks is a pain,
29 | especially when [Web Component](https://developer.mozilla.org/en-US/docs/Web/Web_Components) are not an option (e.g. for server side rendering, best performance, etc).
30 |
31 | At present, the [svelte](https://svelte.dev/) framework is developing rapidly.
32 | It is a good backward compatibility solution to make svelte components run in the old `react` or `vue` project,
33 | especially when the team's technology stack is not unified, this provides an idea of cross-framework sharing component.
34 |
35 | `Svere` contains several `adapters` for `React/Vue2/Vue3` which allows you to pass props and respond to events in a way that makes sense for that library.
36 | Also, it provides a [cli](https://github.com/FE-PIRL/svere/blob/master/packages/cli/README.md) to quickly create svelte components that can be shared across components.
37 |
38 | # Install
39 |
40 | With [npm](https://www.npmjs.com/):
41 |
42 | ```bash
43 | npm install @svere/core
44 | ```
45 |
46 | Or with [yarn](https://yarnpkg.com/lang/en/):
47 |
48 | ```bash
49 | yarn add @svere/core
50 | ```
51 | # Usage
52 |
53 | The core of svere exposes several adapter functions, namely `toReact`, `toVue` and `toVue3`.
54 | Each adapter is a simple function that takes a svelte component and a few options and returns a Vue or React component that can be used in Vue templates or JSX as you would expect.
55 |
56 | All adapters have the same signature as below, eg:
57 | ```ts
58 | toReact(Component: SvelteComponent, wrapperProps?: WrapperProps) : Component
59 | ```
60 | - `Component` should be a compiled svelte component, either precompiled or compiled as part of your build step using rollup-plugin-svelte for rollup or svelte-loader from webpack.
61 | - `wrapperProps` (optional) should be an object contains wrapper `element`, `id`, `className` and `styles`.
62 | - `element` : all component have a base wrapper element, by default this is a `` but you can pass in a string to customise this behaviour (eg: 'span', 'li', etc.)
63 | - `id` : add an id attribute to the base wrapper element, by default this is `svelte-wrapper`.
64 | - `className` : add a class attribute to the base wrapper element which you can define styles in your css files.
65 | - `styles` : add an inline styles attribute to the base wrapper element which can override the `className` attribute.
66 |
67 | # Examples
68 |
69 | In the examples below, the [svelte component](https://github.com/FE-PIRL/svere/blob/master/examples/src/Component.svelte) we will be using is a simple component that accepts a prop that will be rendered and emits an event upon clicking a button.
70 | Bundle it to a single file with `umd` format, then it will be imported by other framework conveniently.
71 |
72 | ```sveltehtml
73 |
88 |
89 |
90 | Hello {name}, welcome!
91 |
92 | add count: {count}
93 |
94 |
95 | update name: {name}
96 |
97 |
98 |
99 |
114 | ```
115 |
116 | ## React
117 |
118 | ```jsx
119 | import React, { useState } from "react";
120 | import SvelteComponent from "./svelte-component";
121 | import toReact from '@svere/core/dist/react.js'
122 |
123 | const wrapperProps = {
124 | element: "section",
125 | className: "section-css",
126 | id: "svelte-react",
127 | styles: {
128 | border: "1px solid gray",
129 | },
130 | };
131 | const ReactComponent = toReact(SvelteComponent, wrapperProps);
132 |
133 | const App = () => {
134 | const [name, setName] = useState('ben');
135 | const changeName = () => setName(n => {
136 | return name === 'ben' ? 'yasin' : 'ben'
137 | });
138 |
139 | const handleEventCallback = (e) => {
140 | console.log(e.detail)
141 | };
142 |
143 | const handleWatchCallback = (name) => {
144 | console.log(name)
145 | };
146 |
147 | return (
148 |
149 |
154 |
155 |
156 |
157 | change inner variable name
158 |
159 | );
160 | };
161 | ```
162 |
163 | ## Vue2
164 |
165 | ```vue
166 |
167 |
168 |
173 | change inner variable name
174 |
175 |
176 |
177 |
203 | ```
204 |
205 | ## Vue3
206 |
207 | ```vue
208 |
209 |
214 |
215 | change inner variable name
216 |
217 |
218 |
255 |
256 |
261 | ```
262 |
263 | # Cli
264 | Try svere out locally with our [CLI](https://github.com/FE-PIRL/svere/tree/master/packages/cli)
265 |
266 | With [npm](https://www.npmjs.com/):
267 |
268 | ```bash
269 | npm install @svere/cli
270 | ```
271 |
272 | Or with [yarn](https://yarnpkg.com/lang/en/):
273 |
274 | ```bash
275 | yarn add @svere/cli
276 | ```
277 |
278 | # Todos
279 |
280 | - develop core to add more features, eg: sub-component, slots.
--------------------------------------------------------------------------------
/packages/cli/README.md:
--------------------------------------------------------------------------------
1 | # SVERE CLI
2 |
3 | A CLI for svere.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | English | [简体中文](https://github.com/FE-PIRL/svere/blob/master/packages/cli/README_ZH.md)
13 |
14 | ---
15 |
16 | - [Intro](#intro)
17 | - [Features](#features)
18 | - [Install](#install)
19 | - [Quick Start](#quick-start)
20 | - [Customization](#customization)
21 | - [Publishing](#publishing)
22 | - [API Reference](#api-reference)
23 | - [Author](#author)
24 | - [License](#license)
25 |
26 | # Intro
27 |
28 | Although you can build your own project to produce target files that meet the requirements, you still have a lot of work to do. Our goal is to help you get rid of the tedious work and let you concentrate on the development of business components. `Svere cli` is a zero-config scaffold, involving life cycles of component such as `development`, `packaging`, `syntax checking`, `testing`, `documentation` and `publishing`, to make you having a relaxed component development experience.
29 |
30 | # Features
31 |
32 | * Live reload and watch mode
33 | * Works with Typescript
34 | * Run crypress and Jest via `svere test`
35 | * ESLint and Stylelint with Prettier via `svere lint`
36 | * Run storybook via `svere doc`
37 | * Escape hatches for customization via `svere.config.js` and exported files of [code-specification-unid](https://github.com/FE-PIRL/code-specification-unid)
38 |
39 | # Install
40 |
41 | With [npm](https://www.npmjs.com/):
42 |
43 | ```bash
44 | npm install -g @svere/cli
45 | ```
46 |
47 | Or with [yarn](https://yarnpkg.com/lang/en/):
48 |
49 | ```bash
50 | yarn add global @svere/cli
51 | ```
52 |
53 | # Quick Start
54 |
55 | ```bash
56 | svere create mycom
57 | cd mycom
58 | yarn start
59 | ```
60 |
61 | That's it. You don't need to worry about setting up TypeScript or Rollup or Jest or other plumbing.
62 | Just start editing `src/components/MyComponent.svelte` and go!
63 |
64 | Below is a list of commands you will probably find useful:
65 |
66 | ```npm start``` or ```yarn start```
67 |
68 | Runs the project in development/watch mode. Your project will be rebuilt upon changes.
69 |
70 | ```npm run build``` or ```yarn build```
71 |
72 | Bundles the package to the dist folder. The package is optimized and bundled with Rollup into multiple formats (UMD, and ES Module).
73 |
74 | ```npm test``` or ```yarn test```
75 |
76 | This template uses [Cypress](https://www.cypress.io/) & [testing-library](https://testing-library.com/docs/cypress-testing-library/intro/) for testing.
77 |
78 | It is highly recommended going through their docs if you intend on testing your components.
79 |
80 | You can witness a simple example by running `svere test -co`.
81 |
82 | ```npm run lint``` or ```yarn lint```
83 |
84 | This template integrates with [code-specification-unid](https://github.com/FE-PIRL/code-specification-unid) for linting.
85 |
86 | It is highly recommended going through their docs if you intend on linting your components.
87 |
88 | The default command without options will run Eslint and Stylelint with Prettier.
89 |
90 | ```npm run doc``` or ```yarn doc```
91 |
92 | This template integrates with [Storybook](https://storybook.js.org/) for docs.
93 |
94 | You can generate static doc files by runing `svere doc -b`.
95 |
96 |
97 | # Customization
98 |
99 | ### Rollup
100 |
101 | > **❗⚠️❗ Warning**:
102 | > These modifications will override the default behavior and configuration of SVERE. As such they can invalidate internal guarantees and assumptions. These types of changes can break internal behavior and can be very fragile against updates. Use with discretion!
103 |
104 | SVERE uses Rollup under the hood. The defaults are solid for most packages (Formik uses the defaults!). However, if you do wish to alter the rollup configuration, you can do so by creating a file called `svere.config.js` at the root of your project like so:
105 |
106 | ```js
107 | // Not transpiled with TypeScript or Babel, so use plain Es6/Node.js!
108 | module.exports = {
109 | // This function will run for each entry/format/env combination
110 | rollup(config, options) {
111 | return config; // always return a config.
112 | },
113 | };
114 | ```
115 |
116 | The `options` object contains the following:
117 |
118 | ```tsx
119 | export interface SvereOptions {
120 | // Name of package
121 | name: string;
122 | // Port for dev
123 | port: number;
124 | // path to file
125 | input: string;
126 | // never launch browser automatically
127 | silent: boolean;
128 | // Module format
129 | format: 'umd' | 'esm' | 'iife';
130 | // Environment
131 | env: 'development' | 'production';
132 | // Path to tsconfig file
133 | tsconfig?: string;
134 | // Is error extraction running?
135 | extractErrors?: boolean;
136 | // Is minifying?
137 | minify?: boolean;
138 | // Is this the very first rollup config (and thus should one-off metadata be extracted)?
139 | writeMeta?: boolean;
140 | // Only transpile, do not type check (makes compilation faster)
141 | transpileOnly?: boolean;
142 | }
143 | ```
144 |
145 | #### Example: Adding Postcss
146 |
147 | ```js
148 | const postcss = require('rollup-plugin-postcss');
149 | const autoprefixer = require('autoprefixer');
150 | const cssnano = require('cssnano');
151 |
152 | module.exports = {
153 | rollup(config, options) {
154 | config.plugins.push(
155 | postcss({
156 | plugins: [
157 | autoprefixer(),
158 | cssnano({
159 | preset: 'default',
160 | }),
161 | ],
162 | inject: false,
163 | // only write out CSS for the first bundle (avoids pointless extra files):
164 | extract: !!options.writeMeta,
165 | })
166 | );
167 | return config;
168 | },
169 | };
170 | ```
171 |
172 |
173 | # Publishing
174 |
175 |
176 | # API Reference
177 |
178 | ### ```svere start```
179 |
180 | ```bash
181 | Usage: svere start [options]
182 |
183 | start development server
184 |
185 | Options:
186 | --entry
specify entry file for dev (default: "src/main.ts")
187 | -d, --debug more debug logging (default: false)
188 | -s, --silent never launch the browser (default: false)
189 | -p, --port specify port for dev (default: "5000")
190 | -h, --help display help for command
191 | ```
192 |
193 |
194 | ### ```svere build```
195 |
196 | ```bash
197 | Usage: svere build [options]
198 |
199 | Build your component once and exit
200 |
201 | Options:
202 | --entry specify entry file for build (default: "src/components/index.ts")
203 | --fileName specify fileName exposed in UMD builds
204 | --format specify module format(s) (default: "umd,esm")
205 | --transpileOnly skip type checking (default: true)
206 | -d, --debug more debug logging (default: false)
207 | -bsb, --buildStorybook build storybook to static files (default: false)
208 | -h, --help display help for command
209 | ```
210 |
211 |
212 | ### ```svere test```
213 |
214 | ```bash
215 | Usage: svere test [options]
216 |
217 | Run cypress and jest test runner
218 |
219 | Options:
220 | -co, --cypressOpen run cypress open (default: false)
221 | -p, --port specify port for test (default: "5000")
222 | -h, --help display help for command
223 | ```
224 |
225 |
226 | ### ```svere lint```
227 |
228 | ```bash
229 | Usage: svere lint [options]
230 |
231 | Run eslint and stylelint with prettier
232 |
233 | Options:
234 | -js, --js run eslint with prettier only (default: false)
235 | -css, --css run stylelint with prettier only (default: false)
236 | -f, --format run prettier only (default: false)
237 | -jfs, --jsFiles specify files for eslint (default: "src/**/*.{js,jsx,ts,tsx,svelte}")
238 | -cfs, --cssFiles specify files for stylelint (default: "src/**/*.{less,postcss,css,scss,svelte}")
239 | -ffs, --formatFiles specify files for prettier (default: "src/**/*.{js,json,ts,tsx,svelte,css,less,scss,html,md}")
240 | -h, --help display help for command
241 | ```
242 |
243 |
244 | ### ```svere doc```
245 |
246 | ```bash
247 | Usage: svere doc [options]
248 |
249 | Start storybook for component
250 |
251 | Options:
252 | -p, --port specify port to run storybook (default: "6006")
253 | -b, --build build storybook to static files (default: false)
254 | -h, --help display help for command
255 | ```
256 |
257 | # Author
258 |
259 | [benyasin](https://github.com/benyasin)
260 |
261 | # License
262 |
263 | [MIT](https://oss.ninja/mit/jaredpalmer/)
264 |
265 |
266 | # Todos
267 |
268 | * Add a command to publish the component to npm or cdn
269 |
--------------------------------------------------------------------------------
/examples/dist/index.mjs:
--------------------------------------------------------------------------------
1 | function noop() { }
2 | function run(fn) {
3 | return fn();
4 | }
5 | function blank_object() {
6 | return Object.create(null);
7 | }
8 | function run_all(fns) {
9 | fns.forEach(run);
10 | }
11 | function is_function(thing) {
12 | return typeof thing === 'function';
13 | }
14 | function safe_not_equal(a, b) {
15 | return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
16 | }
17 | function is_empty(obj) {
18 | return Object.keys(obj).length === 0;
19 | }
20 |
21 | function append(target, node) {
22 | target.appendChild(node);
23 | }
24 | function insert(target, node, anchor) {
25 | target.insertBefore(node, anchor || null);
26 | }
27 | function detach(node) {
28 | node.parentNode.removeChild(node);
29 | }
30 | function element(name) {
31 | return document.createElement(name);
32 | }
33 | function text(data) {
34 | return document.createTextNode(data);
35 | }
36 | function space() {
37 | return text(' ');
38 | }
39 | function listen(node, event, handler, options) {
40 | node.addEventListener(event, handler, options);
41 | return () => node.removeEventListener(event, handler, options);
42 | }
43 | function attr(node, attribute, value) {
44 | if (value == null)
45 | node.removeAttribute(attribute);
46 | else if (node.getAttribute(attribute) !== value)
47 | node.setAttribute(attribute, value);
48 | }
49 | function children(element) {
50 | return Array.from(element.childNodes);
51 | }
52 | function set_data(text, data) {
53 | data = '' + data;
54 | if (text.wholeText !== data)
55 | text.data = data;
56 | }
57 | function custom_event(type, detail) {
58 | const e = document.createEvent('CustomEvent');
59 | e.initCustomEvent(type, false, false, detail);
60 | return e;
61 | }
62 |
63 | let current_component;
64 | function set_current_component(component) {
65 | current_component = component;
66 | }
67 | function get_current_component() {
68 | if (!current_component)
69 | throw new Error('Function called outside component initialization');
70 | return current_component;
71 | }
72 | function createEventDispatcher() {
73 | const component = get_current_component();
74 | return (type, detail) => {
75 | const callbacks = component.$$.callbacks[type];
76 | if (callbacks) {
77 | // TODO are there situations where events could be dispatched
78 | // in a server (non-DOM) environment?
79 | const event = custom_event(type, detail);
80 | callbacks.slice().forEach(fn => {
81 | fn.call(component, event);
82 | });
83 | }
84 | };
85 | }
86 |
87 | const dirty_components = [];
88 | const binding_callbacks = [];
89 | const render_callbacks = [];
90 | const flush_callbacks = [];
91 | const resolved_promise = Promise.resolve();
92 | let update_scheduled = false;
93 | function schedule_update() {
94 | if (!update_scheduled) {
95 | update_scheduled = true;
96 | resolved_promise.then(flush);
97 | }
98 | }
99 | function add_render_callback(fn) {
100 | render_callbacks.push(fn);
101 | }
102 | let flushing = false;
103 | const seen_callbacks = new Set();
104 | function flush() {
105 | if (flushing)
106 | return;
107 | flushing = true;
108 | do {
109 | // first, call beforeUpdate functions
110 | // and update components
111 | for (let i = 0; i < dirty_components.length; i += 1) {
112 | const component = dirty_components[i];
113 | set_current_component(component);
114 | update(component.$$);
115 | }
116 | set_current_component(null);
117 | dirty_components.length = 0;
118 | while (binding_callbacks.length)
119 | binding_callbacks.pop()();
120 | // then, once components are updated, call
121 | // afterUpdate functions. This may cause
122 | // subsequent updates...
123 | for (let i = 0; i < render_callbacks.length; i += 1) {
124 | const callback = render_callbacks[i];
125 | if (!seen_callbacks.has(callback)) {
126 | // ...so guard against infinite loops
127 | seen_callbacks.add(callback);
128 | callback();
129 | }
130 | }
131 | render_callbacks.length = 0;
132 | } while (dirty_components.length);
133 | while (flush_callbacks.length) {
134 | flush_callbacks.pop()();
135 | }
136 | update_scheduled = false;
137 | flushing = false;
138 | seen_callbacks.clear();
139 | }
140 | function update($$) {
141 | if ($$.fragment !== null) {
142 | $$.update();
143 | run_all($$.before_update);
144 | const dirty = $$.dirty;
145 | $$.dirty = [-1];
146 | $$.fragment && $$.fragment.p($$.ctx, dirty);
147 | $$.after_update.forEach(add_render_callback);
148 | }
149 | }
150 | const outroing = new Set();
151 | function transition_in(block, local) {
152 | if (block && block.i) {
153 | outroing.delete(block);
154 | block.i(local);
155 | }
156 | }
157 | function mount_component(component, target, anchor, customElement) {
158 | const { fragment, on_mount, on_destroy, after_update } = component.$$;
159 | fragment && fragment.m(target, anchor);
160 | if (!customElement) {
161 | // onMount happens before the initial afterUpdate
162 | add_render_callback(() => {
163 | const new_on_destroy = on_mount.map(run).filter(is_function);
164 | if (on_destroy) {
165 | on_destroy.push(...new_on_destroy);
166 | }
167 | else {
168 | // Edge case - component was destroyed immediately,
169 | // most likely as a result of a binding initialising
170 | run_all(new_on_destroy);
171 | }
172 | component.$$.on_mount = [];
173 | });
174 | }
175 | after_update.forEach(add_render_callback);
176 | }
177 | function destroy_component(component, detaching) {
178 | const $$ = component.$$;
179 | if ($$.fragment !== null) {
180 | run_all($$.on_destroy);
181 | $$.fragment && $$.fragment.d(detaching);
182 | // TODO null out other refs, including component.$$ (but need to
183 | // preserve final state?)
184 | $$.on_destroy = $$.fragment = null;
185 | $$.ctx = [];
186 | }
187 | }
188 | function make_dirty(component, i) {
189 | if (component.$$.dirty[0] === -1) {
190 | dirty_components.push(component);
191 | schedule_update();
192 | component.$$.dirty.fill(0);
193 | }
194 | component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31));
195 | }
196 | function init(component, options, instance, create_fragment, not_equal, props, dirty = [-1]) {
197 | const parent_component = current_component;
198 | set_current_component(component);
199 | const $$ = component.$$ = {
200 | fragment: null,
201 | ctx: null,
202 | // state
203 | props,
204 | update: noop,
205 | not_equal,
206 | bound: blank_object(),
207 | // lifecycle
208 | on_mount: [],
209 | on_destroy: [],
210 | on_disconnect: [],
211 | before_update: [],
212 | after_update: [],
213 | context: new Map(parent_component ? parent_component.$$.context : options.context || []),
214 | // everything else
215 | callbacks: blank_object(),
216 | dirty,
217 | skip_bound: false
218 | };
219 | let ready = false;
220 | $$.ctx = instance
221 | ? instance(component, options.props || {}, (i, ret, ...rest) => {
222 | const value = rest.length ? rest[0] : ret;
223 | if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
224 | if (!$$.skip_bound && $$.bound[i])
225 | $$.bound[i](value);
226 | if (ready)
227 | make_dirty(component, i);
228 | }
229 | return ret;
230 | })
231 | : [];
232 | $$.update();
233 | ready = true;
234 | run_all($$.before_update);
235 | // `false` as a special case of no DOM component
236 | $$.fragment = create_fragment ? create_fragment($$.ctx) : false;
237 | if (options.target) {
238 | if (options.hydrate) {
239 | const nodes = children(options.target);
240 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
241 | $$.fragment && $$.fragment.l(nodes);
242 | nodes.forEach(detach);
243 | }
244 | else {
245 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
246 | $$.fragment && $$.fragment.c();
247 | }
248 | if (options.intro)
249 | transition_in(component.$$.fragment);
250 | mount_component(component, options.target, options.anchor, options.customElement);
251 | flush();
252 | }
253 | set_current_component(parent_component);
254 | }
255 | /**
256 | * Base class for Svelte components. Used when dev=false.
257 | */
258 | class SvelteComponent {
259 | $destroy() {
260 | destroy_component(this, 1);
261 | this.$destroy = noop;
262 | }
263 | $on(type, callback) {
264 | const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
265 | callbacks.push(callback);
266 | return () => {
267 | const index = callbacks.indexOf(callback);
268 | if (index !== -1)
269 | callbacks.splice(index, 1);
270 | };
271 | }
272 | $set($$props) {
273 | if (this.$$set && !is_empty($$props)) {
274 | this.$$.skip_bound = true;
275 | this.$$set($$props);
276 | this.$$.skip_bound = false;
277 | }
278 | }
279 | }
280 |
281 | /* src/Component.svelte generated by Svelte v3.38.2 */
282 |
283 | function add_css() {
284 | var style = element("style");
285 | style.id = "svelte-4hq7sh-style";
286 | style.textContent = "main.svelte-4hq7sh{text-align:center;padding:1em;max-width:240px;margin:0 auto}h1.svelte-4hq7sh{color:#ff3e00;text-transform:uppercase;font-size:4em;font-weight:100}";
287 | append(document.head, style);
288 | }
289 |
290 | function create_fragment(ctx) {
291 | let main;
292 | let h1;
293 | let t0;
294 | let t1;
295 | let t2;
296 | let t3;
297 | let button0;
298 | let t4;
299 | let t5;
300 | let t6;
301 | let button1;
302 | let t7;
303 | let t8;
304 | let mounted;
305 | let dispose;
306 |
307 | return {
308 | c() {
309 | main = element("main");
310 | h1 = element("h1");
311 | t0 = text("Hello ");
312 | t1 = text(/*name*/ ctx[0]);
313 | t2 = text("!");
314 | t3 = space();
315 | button0 = element("button");
316 | t4 = text("add count: ");
317 | t5 = text(/*count*/ ctx[1]);
318 | t6 = space();
319 | button1 = element("button");
320 | t7 = text("update name: ");
321 | t8 = text(/*name*/ ctx[0]);
322 | attr(h1, "class", "svelte-4hq7sh");
323 | attr(main, "class", "svelte-4hq7sh");
324 | },
325 | m(target, anchor) {
326 | insert(target, main, anchor);
327 | append(main, h1);
328 | append(h1, t0);
329 | append(h1, t1);
330 | append(h1, t2);
331 | append(main, t3);
332 | append(main, button0);
333 | append(button0, t4);
334 | append(button0, t5);
335 | append(main, t6);
336 | append(main, button1);
337 | append(button1, t7);
338 | append(button1, t8);
339 |
340 | if (!mounted) {
341 | dispose = [
342 | listen(button0, "click", /*handleChangeCount*/ ctx[2]),
343 | listen(button1, "click", /*handleChangeName*/ ctx[3])
344 | ];
345 |
346 | mounted = true;
347 | }
348 | },
349 | p(ctx, [dirty]) {
350 | if (dirty & /*name*/ 1) set_data(t1, /*name*/ ctx[0]);
351 | if (dirty & /*count*/ 2) set_data(t5, /*count*/ ctx[1]);
352 | if (dirty & /*name*/ 1) set_data(t8, /*name*/ ctx[0]);
353 | },
354 | i: noop,
355 | o: noop,
356 | d(detaching) {
357 | if (detaching) detach(main);
358 | mounted = false;
359 | run_all(dispose);
360 | }
361 | };
362 | }
363 |
364 | function instance($$self, $$props, $$invalidate) {
365 | const dispatch = createEventDispatcher();
366 | let { name } = $$props;
367 | let count = 0;
368 |
369 | function handleChangeCount(event) {
370 | $$invalidate(1, count += 1);
371 | dispatch("someEvent", count);
372 | }
373 |
374 | function handleChangeName() {
375 | $$invalidate(0, name = "boss");
376 | }
377 |
378 | $$self.$$set = $$props => {
379 | if ("name" in $$props) $$invalidate(0, name = $$props.name);
380 | };
381 |
382 | return [name, count, handleChangeCount, handleChangeName];
383 | }
384 |
385 | class Component extends SvelteComponent {
386 | constructor(options) {
387 | super();
388 | if (!document.getElementById("svelte-4hq7sh-style")) add_css();
389 | init(this, options, instance, create_fragment, safe_not_equal, { name: 0 });
390 | }
391 | }
392 |
393 | export default Component;
394 |
--------------------------------------------------------------------------------
/examples/dist/index.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 | typeof define === 'function' && define.amd ? define(factory) :
4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Examples = factory());
5 | }(this, (function () { 'use strict';
6 |
7 | function noop() { }
8 | function run(fn) {
9 | return fn();
10 | }
11 | function blank_object() {
12 | return Object.create(null);
13 | }
14 | function run_all(fns) {
15 | fns.forEach(run);
16 | }
17 | function is_function(thing) {
18 | return typeof thing === 'function';
19 | }
20 | function safe_not_equal(a, b) {
21 | return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
22 | }
23 | function is_empty(obj) {
24 | return Object.keys(obj).length === 0;
25 | }
26 |
27 | function append(target, node) {
28 | target.appendChild(node);
29 | }
30 | function insert(target, node, anchor) {
31 | target.insertBefore(node, anchor || null);
32 | }
33 | function detach(node) {
34 | node.parentNode.removeChild(node);
35 | }
36 | function element(name) {
37 | return document.createElement(name);
38 | }
39 | function text(data) {
40 | return document.createTextNode(data);
41 | }
42 | function space() {
43 | return text(' ');
44 | }
45 | function listen(node, event, handler, options) {
46 | node.addEventListener(event, handler, options);
47 | return () => node.removeEventListener(event, handler, options);
48 | }
49 | function attr(node, attribute, value) {
50 | if (value == null)
51 | node.removeAttribute(attribute);
52 | else if (node.getAttribute(attribute) !== value)
53 | node.setAttribute(attribute, value);
54 | }
55 | function children(element) {
56 | return Array.from(element.childNodes);
57 | }
58 | function set_data(text, data) {
59 | data = '' + data;
60 | if (text.wholeText !== data)
61 | text.data = data;
62 | }
63 | function custom_event(type, detail) {
64 | const e = document.createEvent('CustomEvent');
65 | e.initCustomEvent(type, false, false, detail);
66 | return e;
67 | }
68 |
69 | let current_component;
70 | function set_current_component(component) {
71 | current_component = component;
72 | }
73 | function get_current_component() {
74 | if (!current_component)
75 | throw new Error('Function called outside component initialization');
76 | return current_component;
77 | }
78 | function createEventDispatcher() {
79 | const component = get_current_component();
80 | return (type, detail) => {
81 | const callbacks = component.$$.callbacks[type];
82 | if (callbacks) {
83 | // TODO are there situations where events could be dispatched
84 | // in a server (non-DOM) environment?
85 | const event = custom_event(type, detail);
86 | callbacks.slice().forEach(fn => {
87 | fn.call(component, event);
88 | });
89 | }
90 | };
91 | }
92 |
93 | const dirty_components = [];
94 | const binding_callbacks = [];
95 | const render_callbacks = [];
96 | const flush_callbacks = [];
97 | const resolved_promise = Promise.resolve();
98 | let update_scheduled = false;
99 | function schedule_update() {
100 | if (!update_scheduled) {
101 | update_scheduled = true;
102 | resolved_promise.then(flush);
103 | }
104 | }
105 | function add_render_callback(fn) {
106 | render_callbacks.push(fn);
107 | }
108 | let flushing = false;
109 | const seen_callbacks = new Set();
110 | function flush() {
111 | if (flushing)
112 | return;
113 | flushing = true;
114 | do {
115 | // first, call beforeUpdate functions
116 | // and update components
117 | for (let i = 0; i < dirty_components.length; i += 1) {
118 | const component = dirty_components[i];
119 | set_current_component(component);
120 | update(component.$$);
121 | }
122 | set_current_component(null);
123 | dirty_components.length = 0;
124 | while (binding_callbacks.length)
125 | binding_callbacks.pop()();
126 | // then, once components are updated, call
127 | // afterUpdate functions. This may cause
128 | // subsequent updates...
129 | for (let i = 0; i < render_callbacks.length; i += 1) {
130 | const callback = render_callbacks[i];
131 | if (!seen_callbacks.has(callback)) {
132 | // ...so guard against infinite loops
133 | seen_callbacks.add(callback);
134 | callback();
135 | }
136 | }
137 | render_callbacks.length = 0;
138 | } while (dirty_components.length);
139 | while (flush_callbacks.length) {
140 | flush_callbacks.pop()();
141 | }
142 | update_scheduled = false;
143 | flushing = false;
144 | seen_callbacks.clear();
145 | }
146 | function update($$) {
147 | if ($$.fragment !== null) {
148 | $$.update();
149 | run_all($$.before_update);
150 | const dirty = $$.dirty;
151 | $$.dirty = [-1];
152 | $$.fragment && $$.fragment.p($$.ctx, dirty);
153 | $$.after_update.forEach(add_render_callback);
154 | }
155 | }
156 | const outroing = new Set();
157 | function transition_in(block, local) {
158 | if (block && block.i) {
159 | outroing.delete(block);
160 | block.i(local);
161 | }
162 | }
163 | function mount_component(component, target, anchor, customElement) {
164 | const { fragment, on_mount, on_destroy, after_update } = component.$$;
165 | fragment && fragment.m(target, anchor);
166 | if (!customElement) {
167 | // onMount happens before the initial afterUpdate
168 | add_render_callback(() => {
169 | const new_on_destroy = on_mount.map(run).filter(is_function);
170 | if (on_destroy) {
171 | on_destroy.push(...new_on_destroy);
172 | }
173 | else {
174 | // Edge case - component was destroyed immediately,
175 | // most likely as a result of a binding initialising
176 | run_all(new_on_destroy);
177 | }
178 | component.$$.on_mount = [];
179 | });
180 | }
181 | after_update.forEach(add_render_callback);
182 | }
183 | function destroy_component(component, detaching) {
184 | const $$ = component.$$;
185 | if ($$.fragment !== null) {
186 | run_all($$.on_destroy);
187 | $$.fragment && $$.fragment.d(detaching);
188 | // TODO null out other refs, including component.$$ (but need to
189 | // preserve final state?)
190 | $$.on_destroy = $$.fragment = null;
191 | $$.ctx = [];
192 | }
193 | }
194 | function make_dirty(component, i) {
195 | if (component.$$.dirty[0] === -1) {
196 | dirty_components.push(component);
197 | schedule_update();
198 | component.$$.dirty.fill(0);
199 | }
200 | component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31));
201 | }
202 | function init(component, options, instance, create_fragment, not_equal, props, dirty = [-1]) {
203 | const parent_component = current_component;
204 | set_current_component(component);
205 | const $$ = component.$$ = {
206 | fragment: null,
207 | ctx: null,
208 | // state
209 | props,
210 | update: noop,
211 | not_equal,
212 | bound: blank_object(),
213 | // lifecycle
214 | on_mount: [],
215 | on_destroy: [],
216 | on_disconnect: [],
217 | before_update: [],
218 | after_update: [],
219 | context: new Map(parent_component ? parent_component.$$.context : options.context || []),
220 | // everything else
221 | callbacks: blank_object(),
222 | dirty,
223 | skip_bound: false
224 | };
225 | let ready = false;
226 | $$.ctx = instance
227 | ? instance(component, options.props || {}, (i, ret, ...rest) => {
228 | const value = rest.length ? rest[0] : ret;
229 | if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
230 | if (!$$.skip_bound && $$.bound[i])
231 | $$.bound[i](value);
232 | if (ready)
233 | make_dirty(component, i);
234 | }
235 | return ret;
236 | })
237 | : [];
238 | $$.update();
239 | ready = true;
240 | run_all($$.before_update);
241 | // `false` as a special case of no DOM component
242 | $$.fragment = create_fragment ? create_fragment($$.ctx) : false;
243 | if (options.target) {
244 | if (options.hydrate) {
245 | const nodes = children(options.target);
246 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
247 | $$.fragment && $$.fragment.l(nodes);
248 | nodes.forEach(detach);
249 | }
250 | else {
251 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
252 | $$.fragment && $$.fragment.c();
253 | }
254 | if (options.intro)
255 | transition_in(component.$$.fragment);
256 | mount_component(component, options.target, options.anchor, options.customElement);
257 | flush();
258 | }
259 | set_current_component(parent_component);
260 | }
261 | /**
262 | * Base class for Svelte components. Used when dev=false.
263 | */
264 | class SvelteComponent {
265 | $destroy() {
266 | destroy_component(this, 1);
267 | this.$destroy = noop;
268 | }
269 | $on(type, callback) {
270 | const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
271 | callbacks.push(callback);
272 | return () => {
273 | const index = callbacks.indexOf(callback);
274 | if (index !== -1)
275 | callbacks.splice(index, 1);
276 | };
277 | }
278 | $set($$props) {
279 | if (this.$$set && !is_empty($$props)) {
280 | this.$$.skip_bound = true;
281 | this.$$set($$props);
282 | this.$$.skip_bound = false;
283 | }
284 | }
285 | }
286 |
287 | /* src/Component.svelte generated by Svelte v3.38.2 */
288 |
289 | function add_css() {
290 | var style = element("style");
291 | style.id = "svelte-4hq7sh-style";
292 | style.textContent = "main.svelte-4hq7sh{text-align:center;padding:1em;max-width:240px;margin:0 auto}h1.svelte-4hq7sh{color:#ff3e00;text-transform:uppercase;font-size:4em;font-weight:100}";
293 | append(document.head, style);
294 | }
295 |
296 | function create_fragment(ctx) {
297 | let main;
298 | let h1;
299 | let t0;
300 | let t1;
301 | let t2;
302 | let t3;
303 | let button0;
304 | let t4;
305 | let t5;
306 | let t6;
307 | let button1;
308 | let t7;
309 | let t8;
310 | let mounted;
311 | let dispose;
312 |
313 | return {
314 | c() {
315 | main = element("main");
316 | h1 = element("h1");
317 | t0 = text("Hello ");
318 | t1 = text(/*name*/ ctx[0]);
319 | t2 = text("!");
320 | t3 = space();
321 | button0 = element("button");
322 | t4 = text("add count: ");
323 | t5 = text(/*count*/ ctx[1]);
324 | t6 = space();
325 | button1 = element("button");
326 | t7 = text("update name: ");
327 | t8 = text(/*name*/ ctx[0]);
328 | attr(h1, "class", "svelte-4hq7sh");
329 | attr(main, "class", "svelte-4hq7sh");
330 | },
331 | m(target, anchor) {
332 | insert(target, main, anchor);
333 | append(main, h1);
334 | append(h1, t0);
335 | append(h1, t1);
336 | append(h1, t2);
337 | append(main, t3);
338 | append(main, button0);
339 | append(button0, t4);
340 | append(button0, t5);
341 | append(main, t6);
342 | append(main, button1);
343 | append(button1, t7);
344 | append(button1, t8);
345 |
346 | if (!mounted) {
347 | dispose = [
348 | listen(button0, "click", /*handleChangeCount*/ ctx[2]),
349 | listen(button1, "click", /*handleChangeName*/ ctx[3])
350 | ];
351 |
352 | mounted = true;
353 | }
354 | },
355 | p(ctx, [dirty]) {
356 | if (dirty & /*name*/ 1) set_data(t1, /*name*/ ctx[0]);
357 | if (dirty & /*count*/ 2) set_data(t5, /*count*/ ctx[1]);
358 | if (dirty & /*name*/ 1) set_data(t8, /*name*/ ctx[0]);
359 | },
360 | i: noop,
361 | o: noop,
362 | d(detaching) {
363 | if (detaching) detach(main);
364 | mounted = false;
365 | run_all(dispose);
366 | }
367 | };
368 | }
369 |
370 | function instance($$self, $$props, $$invalidate) {
371 | const dispatch = createEventDispatcher();
372 | let { name } = $$props;
373 | let count = 0;
374 |
375 | function handleChangeCount(event) {
376 | $$invalidate(1, count += 1);
377 | dispatch("someEvent", count);
378 | }
379 |
380 | function handleChangeName() {
381 | $$invalidate(0, name = "boss");
382 | }
383 |
384 | $$self.$$set = $$props => {
385 | if ("name" in $$props) $$invalidate(0, name = $$props.name);
386 | };
387 |
388 | return [name, count, handleChangeCount, handleChangeName];
389 | }
390 |
391 | class Component extends SvelteComponent {
392 | constructor(options) {
393 | super();
394 | if (!document.getElementById("svelte-4hq7sh-style")) add_css();
395 | init(this, options, instance, create_fragment, safe_not_equal, { name: 0 });
396 | }
397 | }
398 |
399 | return Component;
400 |
401 | })));
402 |
--------------------------------------------------------------------------------