leanweb 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +712 -0
- package/commands/build.js +160 -0
- package/commands/clean.js +8 -0
- package/commands/destroy.js +24 -0
- package/commands/dist.js +61 -0
- package/commands/electron.js +59 -0
- package/commands/generate.js +50 -0
- package/commands/help.js +32 -0
- package/commands/init.js +101 -0
- package/commands/serve.js +71 -0
- package/commands/upgrade.js +53 -0
- package/commands/utils.js +237 -0
- package/commands/version.js +2 -0
- package/leanweb.js +56 -0
- package/lib/lw-html-parser.js +113 -0
- package/package.json +43 -0
- package/templates/component.js +48 -0
- package/templates/electron.js +43 -0
- package/templates/env/prod.js +3 -0
- package/templates/env/test.js +3 -0
- package/templates/env.js +3 -0
- package/templates/favicon.svg +7 -0
- package/templates/index.html +13 -0
- package/templates/lib/api-client.js +74 -0
- package/templates/lib/lw-element.js +483 -0
- package/templates/lib/lw-event-bus.js +54 -0
- package/templates/lib/lw-expr-parser.js +156 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const sass = require('sass');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const net = require('net');
|
|
5
|
+
|
|
6
|
+
const dirs = {
|
|
7
|
+
src: 'src',
|
|
8
|
+
build: 'build',
|
|
9
|
+
serve: 'serve',
|
|
10
|
+
dist: 'dist',
|
|
11
|
+
electron: 'electron',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
module.exports.exec = command => execSync(command, { encoding: 'utf8', stdio: 'inherit' });
|
|
15
|
+
|
|
16
|
+
module.exports.buildCSS = (scssString, currentPaths) => {
|
|
17
|
+
if (scssString.trim()) {
|
|
18
|
+
const includePaths = [currentPaths, path.resolve(process.cwd(), dirs.build), path.resolve(process.cwd(), 'node_modules')];
|
|
19
|
+
const cssResult = sass.renderSync({ data: scssString, includePaths });
|
|
20
|
+
return cssResult.css.toString().trim();
|
|
21
|
+
}
|
|
22
|
+
return '';
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
module.exports.getComponentName = cmp => {
|
|
26
|
+
const indexOfLastSlash = cmp.lastIndexOf('/');
|
|
27
|
+
if (indexOfLastSlash > -1) {
|
|
28
|
+
return cmp.substring(indexOfLastSlash + 1);
|
|
29
|
+
}
|
|
30
|
+
return cmp;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
module.exports.getPathLevels = filePath => {
|
|
34
|
+
filePath = path.normalize(filePath);
|
|
35
|
+
const numSlashes = filePath.replace(/[^\/]/g, '').length;
|
|
36
|
+
let ret = '';
|
|
37
|
+
for (let i = 0; i < numSlashes; ++i) {
|
|
38
|
+
ret += '../';
|
|
39
|
+
}
|
|
40
|
+
return ret;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
module.exports.throttle = (callback, limit = 100) => {
|
|
44
|
+
let wait = false;
|
|
45
|
+
return function () {
|
|
46
|
+
if (!wait) {
|
|
47
|
+
wait = true;
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
wait = false;
|
|
50
|
+
callback.apply(null, arguments);
|
|
51
|
+
}, limit);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
module.exports.getWebPackConfig = (outputDir, project) => {
|
|
57
|
+
return {
|
|
58
|
+
entry: process.cwd() + `/${dirs.build}/${project.name}.js`,
|
|
59
|
+
output: {
|
|
60
|
+
path: process.cwd() + `/${outputDir}/`,
|
|
61
|
+
filename: `${project.name}.js`,
|
|
62
|
+
},
|
|
63
|
+
module: {
|
|
64
|
+
rules: [{
|
|
65
|
+
test: path.resolve(process.cwd()),
|
|
66
|
+
exclude: /node_modules/,
|
|
67
|
+
loader: require.resolve('babel-loader'),
|
|
68
|
+
options: {
|
|
69
|
+
presets: [require.resolve('@babel/preset-env'), {
|
|
70
|
+
plugins: [
|
|
71
|
+
'@babel/plugin-transform-runtime'
|
|
72
|
+
].map(require.resolve)
|
|
73
|
+
}]
|
|
74
|
+
},
|
|
75
|
+
}, {
|
|
76
|
+
test: /\.(scss|sass)$/i,
|
|
77
|
+
use: [
|
|
78
|
+
{
|
|
79
|
+
loader: require.resolve('css-loader'),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
loader: require.resolve('sass-loader'),
|
|
83
|
+
options: {
|
|
84
|
+
sassOptions: {
|
|
85
|
+
includePaths: [path.resolve(process.cwd(), 'node_modules')],
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
}, {
|
|
91
|
+
test: /\.json$/i,
|
|
92
|
+
loader: require.resolve('json5-loader'),
|
|
93
|
+
options: {
|
|
94
|
+
esModule: true,
|
|
95
|
+
},
|
|
96
|
+
type: 'javascript/auto',
|
|
97
|
+
}, {
|
|
98
|
+
loader: require.resolve('raw-loader'),
|
|
99
|
+
exclude: [
|
|
100
|
+
/\.(js|mjs|jsx|ts|tsx)$/i,
|
|
101
|
+
/\.(json|json5)$/i,
|
|
102
|
+
/\.(css|scss|sass)$/i
|
|
103
|
+
],
|
|
104
|
+
}]
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
module.exports.portInUse = (port, address = '127.0.0.1') => {
|
|
110
|
+
return new Promise((resolve, reject) => {
|
|
111
|
+
const server = net.createServer(socket => socket.pipe(socket));
|
|
112
|
+
|
|
113
|
+
server.listen(port, address);
|
|
114
|
+
server.on('error', e => {
|
|
115
|
+
resolve(true);
|
|
116
|
+
});
|
|
117
|
+
server.on('listening', e => {
|
|
118
|
+
server.close();
|
|
119
|
+
resolve(false);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
module.exports.dirs = dirs;
|
|
125
|
+
|
|
126
|
+
const initNote = `Usage: leanweb init or leanweb init project-name
|
|
127
|
+
leanweb init will initialize a leanweb project with the name of the current
|
|
128
|
+
working directory, otherwise, if a project-name is provided, the provided
|
|
129
|
+
project-name will be used as the leanweb project name.
|
|
130
|
+
|
|
131
|
+
leanweb init command will create src/leanweb.json file, which looks like:
|
|
132
|
+
{
|
|
133
|
+
"name": "demo",
|
|
134
|
+
"version": "0.4.5",
|
|
135
|
+
"components": [
|
|
136
|
+
"demo-root",
|
|
137
|
+
],
|
|
138
|
+
"resources": [
|
|
139
|
+
"resources/"
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
where demo is the project name.
|
|
143
|
+
|
|
144
|
+
A src/ directory will be created, and the top level web component demo-root
|
|
145
|
+
will be created. demo-root web component contains 3 files:
|
|
146
|
+
|
|
147
|
+
root.html
|
|
148
|
+
root.js
|
|
149
|
+
root.scss
|
|
150
|
+
|
|
151
|
+
Under src/ directory, global-styles.scss is created for global styling.
|
|
152
|
+
`;
|
|
153
|
+
|
|
154
|
+
const generateNote = `Usage: leanweb generate component-name
|
|
155
|
+
For example leanweb g login will create demo-login web component in
|
|
156
|
+
src/components directory. The leanweb.json will be updated to look like:
|
|
157
|
+
|
|
158
|
+
{
|
|
159
|
+
"name": "demo",
|
|
160
|
+
"version": "0.4.5",
|
|
161
|
+
"components": [
|
|
162
|
+
"root",
|
|
163
|
+
"login"
|
|
164
|
+
],
|
|
165
|
+
"resources": [
|
|
166
|
+
"resources/"
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
demo-login web component will contain 3 files:
|
|
171
|
+
|
|
172
|
+
login.html
|
|
173
|
+
login.js
|
|
174
|
+
login.scss
|
|
175
|
+
|
|
176
|
+
Now, the demo-login component can be added in root.html as follows:
|
|
177
|
+
<demo-login></demo-login>
|
|
178
|
+
`;
|
|
179
|
+
|
|
180
|
+
const serveNote = `Usage: leabweb [env] serve or lw s [env]
|
|
181
|
+
Running this command will start the dev server and open the app in a new
|
|
182
|
+
browser window. Any chances to the source code will cause the dev server to
|
|
183
|
+
reload the app and the browser will be automatically refreshed.
|
|
184
|
+
`;
|
|
185
|
+
|
|
186
|
+
const buildNote = `Usage: leanweb build [env]
|
|
187
|
+
This will build the app and the output files will be stored in the build/
|
|
188
|
+
directory. In this phase, the build doesn't transpile the app code. So likely
|
|
189
|
+
the build file will only work with latest Chrome. However, the dist will
|
|
190
|
+
produce output for most desktop and mobile browsers.
|
|
191
|
+
`;
|
|
192
|
+
|
|
193
|
+
const distNote = `Usage: leanweb dist [env]
|
|
194
|
+
This will transpile the source code and produce output compatible with most
|
|
195
|
+
desktop and mobile browsers. The output will be stored in dist/ directory.
|
|
196
|
+
`;
|
|
197
|
+
|
|
198
|
+
const cleanNote = `Usage: leanweb clean
|
|
199
|
+
This will remove the build and dist directory.
|
|
200
|
+
`;
|
|
201
|
+
|
|
202
|
+
const upgradeNote = `Usage: leanweb upgrade
|
|
203
|
+
This will upgrade leanweb runtime in the src/lib directory.
|
|
204
|
+
`;
|
|
205
|
+
|
|
206
|
+
const electronNote = `Usage: leanweb electron [env]
|
|
207
|
+
This will run the app as native desktop app using Electron.
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
const destroyNote = `Usage leanweb destroy project-name
|
|
211
|
+
This will remove the src/, build/ and dist/ directory. Please
|
|
212
|
+
note the src directory will be deleted by this command.
|
|
213
|
+
`
|
|
214
|
+
|
|
215
|
+
const helpNote = `Usage: leanweb help target-name
|
|
216
|
+
This will show help information of each target. All target names could be
|
|
217
|
+
abbreviated as long as there is no ambiguity. For example:
|
|
218
|
+
leanweb help build is the same as leanweb h b
|
|
219
|
+
leanweb generate login is the same as leanweb g login
|
|
220
|
+
`;
|
|
221
|
+
|
|
222
|
+
const versionNote = `Usage: leanweb version
|
|
223
|
+
Print version information for leanweb.`;
|
|
224
|
+
|
|
225
|
+
module.exports.targets = {
|
|
226
|
+
'init': { file: 'init.js', note: initNote },
|
|
227
|
+
'generate': { file: 'generate.js', note: generateNote },
|
|
228
|
+
'serve': { file: 'serve.js', note: serveNote },
|
|
229
|
+
'build': { file: 'build.js', note: buildNote },
|
|
230
|
+
'dist': { file: 'dist.js', note: distNote },
|
|
231
|
+
'upgrade': { file: 'upgrade.js', note: upgradeNote },
|
|
232
|
+
'clean': { file: 'clean.js', note: cleanNote },
|
|
233
|
+
'electron': { file: 'electron.js', note: electronNote },
|
|
234
|
+
'destroy': { file: 'destroy.js', note: destroyNote },
|
|
235
|
+
'help': { file: 'help.js', note: helpNote },
|
|
236
|
+
'version': { file: 'version.js', note: versionNote },
|
|
237
|
+
};
|
package/leanweb.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
(async () => {
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const semver = require('semver');
|
|
7
|
+
const utils = require('./commands/utils.js');
|
|
8
|
+
|
|
9
|
+
const args = process.argv;
|
|
10
|
+
|
|
11
|
+
if (args.length < 3) {
|
|
12
|
+
utils.exec('npx lw help');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let target = args[2];
|
|
17
|
+
|
|
18
|
+
const targetCandidates = Object.keys(utils.targets).filter(t => t.startsWith(target));
|
|
19
|
+
if (targetCandidates.length === 0) {
|
|
20
|
+
console.error(`Error: target ${target} not found.`);
|
|
21
|
+
return;
|
|
22
|
+
} else if (targetCandidates.length > 1) {
|
|
23
|
+
targetCandidates.forEach(t => {
|
|
24
|
+
console.log(t);
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
target = targetCandidates[0];
|
|
30
|
+
|
|
31
|
+
const leanwebJSONExisted = fs.existsSync(`${process.cwd()}/${utils.dirs.src}/leanweb.json`);
|
|
32
|
+
|
|
33
|
+
if (!leanwebJSONExisted && target !== 'init' && target !== 'help' && target !== 'version') {
|
|
34
|
+
console.error('Error: leanweb.json not found.');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (leanwebJSONExisted && target === 'version' || target === 'serve' || target === 'dist' || target === 'electron') {
|
|
39
|
+
const leanwebPackageJSON = require(`${__dirname}/package.json`);
|
|
40
|
+
const projectLeanwebJSON = require(`${process.cwd()}/${utils.dirs.src}/leanweb.json`);
|
|
41
|
+
const upgradeAvailable = semver.gt(leanwebPackageJSON.version, projectLeanwebJSON.version);
|
|
42
|
+
if (upgradeAvailable) {
|
|
43
|
+
console.log(`New version of leanweb lib (${projectLeanwebJSON.version} => ${leanwebPackageJSON.version}) is available. Please consider
|
|
44
|
+
running 'lw upgrade' to upgrade your project leanweb lib.`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const projectTooNew = semver.gt(projectLeanwebJSON.version, leanwebPackageJSON.version);
|
|
48
|
+
if (projectTooNew) {
|
|
49
|
+
console.log(`Poject version of leanweb (${projectLeanwebJSON.version} > ${leanwebPackageJSON.version}) is newer than local leanweb tools version.
|
|
50
|
+
Please consider running 'npm i leanweb -g' to upgrade your local leanweb tools.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const targetData = utils.targets[target];
|
|
54
|
+
const command = `node --trace-deprecation ${__dirname}/commands/${targetData.file} ${args.slice(3).join(' ')}`;
|
|
55
|
+
utils.exec(command);
|
|
56
|
+
})();
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const parse5 = require('parse5');
|
|
2
|
+
const parser = require('@babel/parser');
|
|
3
|
+
|
|
4
|
+
let astKey = 0;
|
|
5
|
+
|
|
6
|
+
const removeASTLocation = ast => {
|
|
7
|
+
if (Array.isArray(ast)) {
|
|
8
|
+
ast.forEach(a => removeASTLocation(a));
|
|
9
|
+
} else if (typeof ast === 'object') {
|
|
10
|
+
delete ast['loc'];
|
|
11
|
+
delete ast['start'];
|
|
12
|
+
delete ast['end'];
|
|
13
|
+
const values = Object.values(ast).filter(v => Array.isArray(v) || typeof v === 'object');
|
|
14
|
+
removeASTLocation(values);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const getAST = expr => {
|
|
19
|
+
const parsedProgram = parser.parse(expr).program;
|
|
20
|
+
if (parsedProgram.directives.length > 0 && parsedProgram.body.length === 0) {
|
|
21
|
+
return parsedProgram.directives;
|
|
22
|
+
}
|
|
23
|
+
return parsedProgram.body;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const walkNode = (node, interpolation) => {
|
|
27
|
+
node.attrs && node.attrs.forEach(attr => {
|
|
28
|
+
const { startLine, endLine } = node.sourceCodeLocation;
|
|
29
|
+
const loc = { startLine, endLine };
|
|
30
|
+
const key = `${++astKey}`;
|
|
31
|
+
if (attr.name === 'lw-false' || attr.name === 'lw-context' || attr.name === 'lw-for-parent') {
|
|
32
|
+
// this should never happen
|
|
33
|
+
console.assert(false, attr.name);
|
|
34
|
+
// no op
|
|
35
|
+
} else if (attr.name === 'lw') {
|
|
36
|
+
node.attrs.push({ name: 'lw-elem', value: '' });
|
|
37
|
+
let expr = '';
|
|
38
|
+
if (node.childNodes) {
|
|
39
|
+
const exprNode = node.childNodes.find(childNode => childNode.nodeName === '#text');
|
|
40
|
+
expr = exprNode ? exprNode.value : '';
|
|
41
|
+
}
|
|
42
|
+
const ast = getAST(expr);
|
|
43
|
+
removeASTLocation(ast);
|
|
44
|
+
interpolation[key] = { ast, loc };
|
|
45
|
+
node.childNodes.length = 0;
|
|
46
|
+
attr.value = key;
|
|
47
|
+
} else if (attr.name === ('lw-for')) {
|
|
48
|
+
node.attrs.push({ name: 'lw-elem', value: '' });
|
|
49
|
+
const matched = attr.value.match(/(.+)\s+in\s+(.+)/);
|
|
50
|
+
const itemIndex = matched[1].split(',');
|
|
51
|
+
const itemExpr = itemIndex[0].trim();
|
|
52
|
+
let indexExpr;
|
|
53
|
+
if (itemIndex.length > 1) {
|
|
54
|
+
indexExpr = itemIndex[1].trim();
|
|
55
|
+
}
|
|
56
|
+
const itemsExpr = matched[2];
|
|
57
|
+
const astItems = getAST(itemsExpr);
|
|
58
|
+
removeASTLocation(astItems);
|
|
59
|
+
interpolation[key] = { astItems, loc, itemExpr, indexExpr, itemsExpr };
|
|
60
|
+
attr.value = key;
|
|
61
|
+
} else if (attr.name === ('lw-model')) {
|
|
62
|
+
node.attrs.push({ name: 'lw-elem-bind', value: '' });
|
|
63
|
+
node.attrs.push({ name: 'lw-elem', value: '' });
|
|
64
|
+
const ast = getAST(attr.value);
|
|
65
|
+
removeASTLocation(ast);
|
|
66
|
+
interpolation[key] = { ast, loc };
|
|
67
|
+
attr.value = key;
|
|
68
|
+
} else if (attr.name.startsWith('lw-on:') || attr.name.startsWith('lw-class:') || attr.name.startsWith('lw-bind:') || attr.name.startsWith('lw-input:')) {
|
|
69
|
+
if (attr.name.startsWith('lw-on:') || attr.name.startsWith('lw-input:')) {
|
|
70
|
+
node.attrs.push({ name: 'lw-elem-bind', value: '' });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
node.attrs.push({ name: 'lw-elem', value: '' });
|
|
74
|
+
const lw = attr.name.split(':');
|
|
75
|
+
const lwType = lw[0];
|
|
76
|
+
const lwValue = lw[1];
|
|
77
|
+
|
|
78
|
+
const ast = getAST(attr.value);
|
|
79
|
+
removeASTLocation(ast);
|
|
80
|
+
interpolation[key] = { ast, loc, lwType, lwValue };
|
|
81
|
+
|
|
82
|
+
attr.value = key;
|
|
83
|
+
} else if (attr.name.startsWith('lw-')) {
|
|
84
|
+
node.attrs.push({ name: 'lw-elem', value: '' });
|
|
85
|
+
const ast = getAST(attr.value);
|
|
86
|
+
removeASTLocation(ast);
|
|
87
|
+
interpolation[key] = { ast, loc };
|
|
88
|
+
attr.value = key;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
node.childNodes && node.childNodes.forEach(childNode => walkNode(childNode, interpolation));
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const parse = html => {
|
|
95
|
+
const ast = {};
|
|
96
|
+
const doc = parse5.parseFragment(html, { sourceCodeLocationInfo: true });
|
|
97
|
+
walkNode(doc, ast);
|
|
98
|
+
html = parse5.serialize(doc);
|
|
99
|
+
ast.html = html;
|
|
100
|
+
return ast;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
module.exports = { parse };
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
// const html = `<div>
|
|
107
|
+
// <span class="x" lw>/a/;(1+(2+3))</span>
|
|
108
|
+
// <span lw-on:click="a">dddd</span>
|
|
109
|
+
// <span lw></span>
|
|
110
|
+
// </div>`;
|
|
111
|
+
|
|
112
|
+
// const result = parse(html);
|
|
113
|
+
// console.log(JSON.stringify(result, null, 2));
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "leanweb",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "Builds framework agnostic web components.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"leanweb": "leanweb.js",
|
|
7
|
+
"lw": "leanweb.js"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/elgs/leanweb.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://leanweb.app",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"leanweb",
|
|
16
|
+
"lw",
|
|
17
|
+
"web components"
|
|
18
|
+
],
|
|
19
|
+
"author": "Qian Chen",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@babel/core": "^7.15.5",
|
|
23
|
+
"@babel/parser": "^7.15.6",
|
|
24
|
+
"@babel/plugin-transform-runtime": "^7.15.0",
|
|
25
|
+
"@babel/preset-env": "^7.15.6",
|
|
26
|
+
"babel-loader": "^8.2.2",
|
|
27
|
+
"clean-css": "^5.1.5",
|
|
28
|
+
"css-loader": "^6.2.0",
|
|
29
|
+
"fs-extra": "^10.0.0",
|
|
30
|
+
"globby": "^11.0.4",
|
|
31
|
+
"html-minifier": "^4.0.0",
|
|
32
|
+
"isomorphic-git": "^1.10.0",
|
|
33
|
+
"json5-loader": "^4.0.1",
|
|
34
|
+
"node-watch": "^0.7.1",
|
|
35
|
+
"parse5": "^6.0.1",
|
|
36
|
+
"raw-loader": "^4.0.2",
|
|
37
|
+
"sass": "^1.41.1",
|
|
38
|
+
"sass-loader": "^12.1.0",
|
|
39
|
+
"semver": "^7.3.5",
|
|
40
|
+
"webpack": "^5.53.0",
|
|
41
|
+
"webpack-dev-server": "^4.2.1"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import LWElement from './../../${pathLevels}lib/lw-element.js';
|
|
2
|
+
import ast from './ast.js';
|
|
3
|
+
|
|
4
|
+
customElements.define('${projectName}-${component}',
|
|
5
|
+
class extends LWElement { // LWElement extends HTMLElement
|
|
6
|
+
constructor() {
|
|
7
|
+
super(ast);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// derived from LWElement
|
|
11
|
+
// domReady() {
|
|
12
|
+
// console.log('Dom is ready');
|
|
13
|
+
// }
|
|
14
|
+
|
|
15
|
+
// inputReady() {
|
|
16
|
+
// console.log('input is ready');
|
|
17
|
+
// }
|
|
18
|
+
|
|
19
|
+
// Called when the urlHash changes. This could be useful to update the
|
|
20
|
+
// DOM on component routing.
|
|
21
|
+
// urlHashChanged() {
|
|
22
|
+
// // update component DOM
|
|
23
|
+
// this.update();
|
|
24
|
+
// }
|
|
25
|
+
|
|
26
|
+
// derived from HTMLElement
|
|
27
|
+
// connectedCallback() {
|
|
28
|
+
// console.log(this.isConnected);
|
|
29
|
+
// console.log('Element added to page.');
|
|
30
|
+
// }
|
|
31
|
+
|
|
32
|
+
// disconnectedCallback() {
|
|
33
|
+
// console.log('Element removed from page.');
|
|
34
|
+
// }
|
|
35
|
+
|
|
36
|
+
// adoptedCallback() {
|
|
37
|
+
// console.log('Element moved to new page.');
|
|
38
|
+
// }
|
|
39
|
+
|
|
40
|
+
// static get observedAttributes() {
|
|
41
|
+
// return [];
|
|
42
|
+
// }
|
|
43
|
+
|
|
44
|
+
// attributeChangedCallback(name, oldValue, newValue) {
|
|
45
|
+
// console.log(name, oldValue, newValue);
|
|
46
|
+
// }
|
|
47
|
+
}
|
|
48
|
+
);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const { app, BrowserWindow } = require('electron');
|
|
2
|
+
|
|
3
|
+
const createWindow = () => {
|
|
4
|
+
// Create the browser window.
|
|
5
|
+
const win = new BrowserWindow({
|
|
6
|
+
width: 640,
|
|
7
|
+
height: 480,
|
|
8
|
+
webPreferences: {
|
|
9
|
+
nodeIntegration: true
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
// and load the index.html of the app.
|
|
14
|
+
win.loadFile('index.html');
|
|
15
|
+
|
|
16
|
+
// Open the DevTools.
|
|
17
|
+
// win.webContents.openDevTools();
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// This method will be called when Electron has finished
|
|
21
|
+
// initialization and is ready to create browser windows.
|
|
22
|
+
// Some APIs can only be used after this event occurs.
|
|
23
|
+
app.whenReady().then(createWindow);
|
|
24
|
+
|
|
25
|
+
// Quit when all windows are closed.
|
|
26
|
+
app.on('window-all-closed', () => {
|
|
27
|
+
// On macOS it is common for applications and their menu bar
|
|
28
|
+
// to stay active until the user quits explicitly with Cmd + Q
|
|
29
|
+
if (process.platform !== 'darwin') {
|
|
30
|
+
app.quit();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
app.on('activate', () => {
|
|
35
|
+
// On macOS it's common to re-create a window in the app when the
|
|
36
|
+
// dock icon is clicked and there are no other windows open.
|
|
37
|
+
if (BrowserWindow.getAllWindows().length === 0) {
|
|
38
|
+
createWindow();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// In this file you can include the rest of your app's specific main process
|
|
43
|
+
// code. You can also put them in separate files and require them here.
|
package/templates/env.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg width="400px" height="247px" viewBox="0 0 400 247" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
3
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
4
|
+
<rect id="Rectangle" fill="#FF6347" x="0" y="0" width="400" height="247"></rect>
|
|
5
|
+
<path d="M164.382947,200 L164.382947,182.969188 L94.5504862,182.969188 L94.5504862,48 L77,48 L77,200 L164.382947,200 Z M209.459985,200 L239.942408,72.2689076 L240.311892,72.2689076 L270.424832,200 L288.714286,200 L324,48 L306.449514,48 L279.66193,174.453782 L279.292446,174.453782 L250.103216,48 L231.074794,48 L201.516081,174.453782 L201.146597,174.453782 L175.282723,48 L157.362752,48 L191.170531,200 L209.459985,200 Z" id="LW" fill="#FFFFFF" fill-rule="nonzero"></path>
|
|
6
|
+
</g>
|
|
7
|
+
</svg>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>${project.name}</title>
|
|
6
|
+
<script type="module" src="${project.name}.js"></script>
|
|
7
|
+
<link rel="stylesheet" href="${project.name}.css">
|
|
8
|
+
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
|
9
|
+
</head>
|
|
10
|
+
<body style="opacity: 0;" onload="document.body.style.opacity=1">
|
|
11
|
+
<${project.name}-root></${project.name}-root>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Please don't modify this file. Create one outside of the lib directory with
|
|
2
|
+
// your project speicific configurations. Files in the lib directory is subject
|
|
3
|
+
// to overwrite on Leanweb upgrade.
|
|
4
|
+
|
|
5
|
+
class APIClient {
|
|
6
|
+
constructor(baesUrl, sendToken = false, defaultHeaders = {}) {
|
|
7
|
+
this.baesUrl = baesUrl;
|
|
8
|
+
this.sendToken = sendToken;
|
|
9
|
+
this.defaultHeaders = defaultHeaders;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async _fetch(method, url = '', data = {}, headers = {}) {
|
|
13
|
+
if (!url.toLowerCase().startsWith('https://') && !url.toLowerCase().startsWith('http://')) {
|
|
14
|
+
url = this.baesUrl + url;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (method === 'GET' && data && typeof data === 'object') {
|
|
18
|
+
// encode data and append to url
|
|
19
|
+
const queryString = paramsToQueryString(data);
|
|
20
|
+
data = null;
|
|
21
|
+
if (url.endsWith('?')) {
|
|
22
|
+
url += queryString;
|
|
23
|
+
} else if (url.indexOf('?') >= 0) {
|
|
24
|
+
url += ('&' + queryString);
|
|
25
|
+
} else {
|
|
26
|
+
url += ('?' + queryString);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (this.sendToken) {
|
|
31
|
+
const token = localStorage.getItem('access_token');
|
|
32
|
+
if (token) {
|
|
33
|
+
headers['access_token'] = token;
|
|
34
|
+
} else {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const response = await fetch(url, {
|
|
39
|
+
method,
|
|
40
|
+
headers: { ...this.defaultHeaders, ...headers },
|
|
41
|
+
body: data ? JSON.stringify(data) : null,
|
|
42
|
+
});
|
|
43
|
+
return response.json();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
post(url, data, headers) { return this._fetch('POST', url, data, headers); }
|
|
47
|
+
get(url, data, headers) { return this._fetch('GET', url, data, headers); }
|
|
48
|
+
patch(url, data, headers) { return this._fetch('PATCH', url, data, headers); }
|
|
49
|
+
delete(url, data, headers) { return this._fetch('DELETE', url, data, headers); }
|
|
50
|
+
put(url, data, headers) { return this._fetch('PUT', url, data, headers); }
|
|
51
|
+
options(url, data, headers) { return this._fetch('OPTIONS', url, data, headers); }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const paramsToQueryString = (params) => {
|
|
55
|
+
return Object.keys(params).map(k => {
|
|
56
|
+
const v = params[k];
|
|
57
|
+
if (Array.isArray(v)) {
|
|
58
|
+
return v.reduce((vacc, vcurr) => {
|
|
59
|
+
return `${vacc}${k}=${encodeURIComponent(vcurr)}&`;
|
|
60
|
+
}, '');
|
|
61
|
+
} else {
|
|
62
|
+
return `${k}=${encodeURIComponent(v)}&`;
|
|
63
|
+
}
|
|
64
|
+
}).reduce((acc, curr) => acc + curr, '').slice(0, -1);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// const apiUrl = 'http://localhost:1234';
|
|
68
|
+
// const anotherApiUrl = 'http://127.0.0.1:4321';
|
|
69
|
+
|
|
70
|
+
// export const api = new APIClient(apiUrl, true);
|
|
71
|
+
// export const http = new APIClient(apiUrl);
|
|
72
|
+
|
|
73
|
+
// export const anotherApi = new APIClient(anotherApiUrl, true);
|
|
74
|
+
// export const anotherHttp = new APIClient(anotherApiUrl);
|