├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bin └── fle ├── boilerplate ├── app │ ├── .gitignore.keep │ ├── README.md │ ├── package.json │ └── src │ │ └── example │ │ ├── app.json │ │ ├── hello │ │ ├── images │ │ │ └── logo.png │ │ ├── index.js │ │ └── style.module.css │ │ └── index.js ├── lib │ ├── .gitignore.keep │ ├── .npmignore.keep │ ├── README.md │ ├── package.json │ └── src │ │ ├── common │ │ └── index.js │ │ └── example │ │ ├── app.json │ │ ├── index.html │ │ ├── index.js │ │ └── style.css ├── miniprogram │ ├── .gitignore.keep │ ├── README.md │ ├── app.js │ ├── app.json │ ├── app.wxss │ ├── deps │ │ ├── fundebug.1.0.0.min.js │ │ └── uuid.js │ ├── model │ │ └── fetchAPI.js │ ├── package.json │ ├── pages │ │ └── index │ │ │ ├── index.js │ │ │ ├── index.json │ │ │ ├── index.wxml │ │ │ └── index.wxss │ ├── project.config.json │ └── utils │ │ ├── DATracker.js │ │ ├── config.js │ │ ├── format.js │ │ ├── utils.js │ │ └── wxAPI.js ├── node │ ├── .gitignore.keep │ ├── .npmignore.keep │ ├── README.md │ ├── package.json │ └── src │ │ └── index.js ├── react │ ├── .gitignore.keep │ ├── README.md │ ├── package.json │ └── src │ │ └── example │ │ ├── App.js │ │ ├── app.json │ │ ├── components │ │ └── Hello │ │ │ ├── images │ │ │ └── logo.svg │ │ │ ├── index.js │ │ │ └── style.module.css │ │ ├── global.css │ │ └── index.js └── vue │ ├── .gitignore.keep │ ├── README.md │ ├── package.json │ └── src │ └── example │ ├── App.vue │ ├── app.json │ ├── components │ └── HelloWorld.vue │ ├── images │ └── logo.png │ └── index.js ├── build ├── .share │ ├── images │ │ ├── favicon.ico │ │ └── logo.png │ └── template │ │ ├── default.html │ │ ├── dev.html │ │ ├── h5 │ │ ├── default.html │ │ ├── wenman.ftl │ │ └── wenman.html │ │ └── pc │ │ ├── default.html │ │ └── wenman.html └── webpack │ ├── babel.js │ ├── config.js │ ├── eslint.js │ ├── loader.js │ ├── plugin.js │ ├── plugins │ ├── CopyAssets │ │ └── index.js │ └── NosUpload │ │ └── index.js │ ├── postcss.config.js │ ├── utils.js │ ├── webpack.base.config.js │ ├── webpack.build.config.js │ ├── webpack.dev.config.js │ └── webpack.lib.config.js ├── lib ├── commands │ ├── build.js │ ├── dev.js │ ├── init.js │ ├── lib.js │ ├── sprite.js │ └── upload.js ├── consts.js ├── fix │ └── babel-cli.js ├── install.js ├── json │ ├── cdn.json │ └── fle-webpack.json ├── sprites.js └── utils.js ├── package.build.json ├── package.json ├── tools └── publish.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode/ 3 | node_modules/ 4 | *.log* 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode/ 3 | node_modules/ 4 | *.log* 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## [4.8.1](https://github.com/ansenhuang/fle-cli/compare/v4.8.0...v4.8.1) (2019-03-15) 3 | 4 | 5 | ### Bug Fixes 6 | 7 | * react object-assign ([8ae5e05](https://github.com/ansenhuang/fle-cli/commit/8ae5e05)) 8 | 9 | 10 | 11 | 12 | # [4.8.0](https://github.com/ansenhuang/fle-cli/compare/v4.7.5...v4.8.0) (2019-01-28) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * source map ([c553ded](https://github.com/ansenhuang/fle-cli/commit/c553ded)) 18 | 19 | 20 | 21 | 22 | ## [4.7.5](https://github.com/ansenhuang/fle-cli/compare/v4.7.4...v4.7.5) (2019-01-25) 23 | 24 | 25 | ### Bug Fixes 26 | 27 | * source map ([21b586a](https://github.com/ansenhuang/fle-cli/commit/21b586a)) 28 | 29 | 30 | 31 | 32 | ## [4.7.4](https://github.com/ansenhuang/fle-cli/compare/v4.7.3...v4.7.4) (2019-01-25) 33 | 34 | 35 | ### Features 36 | 37 | * js sourceMap ([315dbd3](https://github.com/ansenhuang/fle-cli/commit/315dbd3)) 38 | 39 | 40 | 41 | 42 | ## [4.7.3](https://github.com/ansenhuang/fle-cli/compare/v4.7.2...v4.7.3) (2019-01-25) 43 | 44 | 45 | ### Bug Fixes 46 | 47 | * install fail ([1408337](https://github.com/ansenhuang/fle-cli/commit/1408337)) 48 | 49 | 50 | 51 | 52 | ## [4.7.2](https://github.com/ansenhuang/fle-cli/compare/v4.7.1...v4.7.2) (2018-10-30) 53 | 54 | 55 | 56 | 57 | ## [4.7.1](https://github.com/ansenhuang/fle-cli/compare/v4.7.0...v4.7.1) (2018-10-30) 58 | 59 | 60 | ### Bug Fixes 61 | 62 | * stylelint ([610b936](https://github.com/ansenhuang/fle-cli/commit/610b936)) 63 | 64 | 65 | 66 | 67 | # [4.7.0](https://github.com/ansenhuang/fle-cli/compare/v4.6.4...v4.7.0) (2018-10-29) 68 | 69 | 70 | 71 | 72 | ## [4.6.4](https://github.com/ansenhuang/fle-cli/compare/v4.6.3...v4.6.4) (2018-10-17) 73 | 74 | 75 | 76 | 77 | ## [4.6.3](https://github.com/ansenhuang/fle-cli/compare/v4.6.2...v4.6.3) (2018-10-03) 78 | 79 | 80 | 81 | 82 | ## [4.6.2](https://github.com/ansenhuang/fle-cli/compare/v4.6.1...v4.6.2) (2018-10-02) 83 | 84 | 85 | ### Bug Fixes 86 | 87 | * node babel ([33a6d61](https://github.com/ansenhuang/fle-cli/commit/33a6d61)) 88 | 89 | 90 | 91 | 92 | ## [4.6.1](https://github.com/ansenhuang/fle-cli/compare/v4.6.0...v4.6.1) (2018-10-02) 93 | 94 | 95 | ### Bug Fixes 96 | 97 | * node babel ([f15a423](https://github.com/ansenhuang/fle-cli/commit/f15a423)) 98 | 99 | 100 | 101 | 102 | # [4.6.0](https://github.com/ansenhuang/fle-cli/compare/v4.5.4...v4.6.0) (2018-09-30) 103 | 104 | 105 | ### Features 106 | 107 | * sprites ([379b185](https://github.com/ansenhuang/fle-cli/commit/379b185)) 108 | 109 | 110 | 111 | 112 | ## [4.5.4](https://github.com/ansenhuang/fle-cli/compare/v4.5.3...v4.5.4) (2018-09-29) 113 | 114 | 115 | ### Bug Fixes 116 | 117 | * windows bug in dirname with space ([9bb578a](https://github.com/ansenhuang/fle-cli/commit/9bb578a)) 118 | 119 | 120 | 121 | 122 | ## [4.5.3](https://github.com/ansenhuang/fle-cli/compare/v4.5.2...v4.5.3) (2018-09-28) 123 | 124 | 125 | 126 | 127 | ## [4.5.2](https://github.com/ansenhuang/fle-cli/compare/v4.5.1...v4.5.2) (2018-09-19) 128 | 129 | 130 | ### Performance Improvements 131 | 132 | * build copy ([3e9955a](https://github.com/ansenhuang/fle-cli/commit/3e9955a)) 133 | 134 | 135 | 136 | 137 | ## [4.5.1](https://github.com/ansenhuang/fle-cli/compare/v4.5.0...v4.5.1) (2018-09-18) 138 | 139 | 140 | ### Features 141 | 142 | * dev build ([0d22746](https://github.com/ansenhuang/fle-cli/commit/0d22746)) 143 | 144 | 145 | 146 | 147 | # [4.5.0](https://github.com/ansenhuang/fle-cli/compare/v4.4.3...v4.5.0) (2018-09-18) 148 | 149 | 150 | ### Features 151 | 152 | * copy at build ([1432e64](https://github.com/ansenhuang/fle-cli/commit/1432e64)) 153 | 154 | 155 | 156 | 157 | ## [4.4.3](https://github.com/ansenhuang/fle-cli/compare/v4.4.2...v4.4.3) (2018-09-07) 158 | 159 | 160 | 161 | 162 | ## [4.4.2](https://github.com/ansenhuang/fle-cli/compare/v4.4.1...v4.4.2) (2018-09-06) 163 | 164 | 165 | 166 | 167 | ## [4.4.1](https://github.com/ansenhuang/fle-cli/compare/v4.4.0...v4.4.1) (2018-08-28) 168 | 169 | 170 | 171 | 172 | # [4.4.0](https://github.com/ansenhuang/fle-cli/compare/v4.3.6...v4.4.0) (2018-08-21) 173 | 174 | 175 | ### Bug Fixes 176 | 177 | * babel ([27d84e4](https://github.com/ansenhuang/fle-cli/commit/27d84e4)) 178 | * babel ([806557c](https://github.com/ansenhuang/fle-cli/commit/806557c)) 179 | 180 | 181 | 182 | 183 | ## [4.3.6](https://github.com/ansenhuang/fle-cli/compare/v4.3.5...v4.3.6) (2018-08-06) 184 | 185 | 186 | 187 | 188 | ## [4.3.5](https://github.com/ansenhuang/fle-cli/compare/v4.3.4...v4.3.5) (2018-07-24) 189 | 190 | 191 | 192 | 193 | ## [4.3.4](https://github.com/ansenhuang/fle-cli/compare/v4.3.3...v4.3.4) (2018-07-24) 194 | 195 | 196 | 197 | 198 | ## [4.3.3](https://github.com/ansenhuang/fle-cli/compare/v4.3.2...v4.3.3) (2018-07-24) 199 | 200 | 201 | ### Bug Fixes 202 | 203 | * require exports.default ([fb8d021](https://github.com/ansenhuang/fle-cli/commit/fb8d021)) 204 | 205 | 206 | ### Features 207 | 208 | * import css with real object ([33e7be1](https://github.com/ansenhuang/fle-cli/commit/33e7be1)) 209 | 210 | 211 | 212 | 213 | ## [4.3.2](https://github.com/ansenhuang/fle-cli/compare/v4.3.2-0...v4.3.2) (2018-07-03) 214 | 215 | 216 | 217 | 218 | ## [4.3.2-0](https://github.com/ansenhuang/fle-cli/compare/v4.3.1...v4.3.2-0) (2018-07-03) 219 | 220 | 221 | 222 | 223 | ## [4.3.1](https://github.com/ansenhuang/fle-cli/compare/v4.3.0...v4.3.1) (2018-07-03) 224 | 225 | 226 | 227 | 228 | # [4.3.0](https://github.com/ansenhuang/fle-cli/compare/v4.2.6...v4.3.0) (2018-07-03) 229 | 230 | 231 | 232 | 233 | ## [4.2.6](https://github.com/ansenhuang/fle-cli/compare/v4.2.5...v4.2.6) (2018-06-29) 234 | 235 | 236 | ### Features 237 | 238 | * update rem ([597f4db](https://github.com/ansenhuang/fle-cli/commit/597f4db)) 239 | 240 | 241 | 242 | 243 | ## [4.2.5](https://github.com/ansenhuang/fle-cli/compare/v4.2.4...v4.2.5) (2018-06-28) 244 | 245 | 246 | 247 | 248 | ## [4.2.4](https://github.com/ansenhuang/fle-cli/compare/v4.2.3...v4.2.4) (2018-06-26) 249 | 250 | 251 | 252 | 253 | ## [4.2.3](https://github.com/ansenhuang/fle-cli/compare/v4.2.2...v4.2.3) (2018-06-25) 254 | 255 | 256 | ### Bug Fixes 257 | 258 | * 创建子页面 ([e873cb8](https://github.com/ansenhuang/fle-cli/commit/e873cb8)) 259 | 260 | 261 | ### Features 262 | 263 | * 定向选择需要编译的页面 ([7db81ee](https://github.com/ansenhuang/fle-cli/commit/7db81ee)) 264 | 265 | 266 | 267 | 268 | ## [4.2.2](https://github.com/ansenhuang/fle-cli/compare/v4.2.1...v4.2.2) (2018-06-21) 269 | 270 | 271 | ### Bug Fixes 272 | 273 | * dev pages ([c87e20c](https://github.com/ansenhuang/fle-cli/commit/c87e20c)) 274 | 275 | 276 | 277 | 278 | ## [4.2.1](https://github.com/ansenhuang/fle-cli/compare/v4.2.0...v4.2.1) (2018-06-20) 279 | 280 | 281 | ### Bug Fixes 282 | 283 | * report ([23f5d6e](https://github.com/ansenhuang/fle-cli/commit/23f5d6e)) 284 | 285 | 286 | ### Features 287 | 288 | * 本地端口检测 ([a4a02d3](https://github.com/ansenhuang/fle-cli/commit/a4a02d3)) 289 | 290 | 291 | 292 | 293 | # [4.2.0](https://github.com/ansenhuang/fle-cli/compare/v4.1.4...v4.2.0) (2018-06-14) 294 | 295 | 296 | ### Features 297 | 298 | * support freemarker template for java ([2264e04](https://github.com/ansenhuang/fle-cli/commit/2264e04)) 299 | 300 | 301 | 302 | 303 | ## [4.1.4](https://github.com/ansenhuang/fle-cli/compare/v4.1.3...v4.1.4) (2018-06-13) 304 | 305 | 306 | ### Bug Fixes 307 | 308 | * splitVendors ([c904c8b](https://github.com/ansenhuang/fle-cli/commit/c904c8b)) 309 | 310 | 311 | 312 | 313 | ## [4.1.3](https://github.com/ansenhuang/fle-cli/compare/v4.1.2...v4.1.3) (2018-06-13) 314 | 315 | 316 | ### Features 317 | 318 | * custom filename ([c32c69e](https://github.com/ansenhuang/fle-cli/commit/c32c69e)) 319 | 320 | 321 | 322 | 323 | ## [4.1.2](https://github.com/ansenhuang/fle-cli/compare/v4.1.1...v4.1.2) (2018-06-13) 324 | 325 | 326 | ### Features 327 | 328 | * stylelint ([264e4f8](https://github.com/ansenhuang/fle-cli/commit/264e4f8)) 329 | 330 | 331 | 332 | 333 | ## [4.1.1](https://github.com/ansenhuang/fle-cli/compare/v4.1.0...v4.1.1) (2018-06-01) 334 | 335 | 336 | ### Bug Fixes 337 | 338 | * rem-resize ([049935e](https://github.com/ansenhuang/fle-cli/commit/049935e)) 339 | 340 | 341 | 342 | 343 | # [4.1.0](https://github.com/ansenhuang/fle-cli/compare/v4.1.0-1...v4.1.0) (2018-05-25) 344 | 345 | 346 | ### Bug Fixes 347 | 348 | * splitChunks commons ([cf6f396](https://github.com/ansenhuang/fle-cli/commit/cf6f396)) 349 | 350 | 351 | 352 | 353 | # [4.1.0-1](https://github.com/ansenhuang/fle-cli/compare/v4.1.0-0...v4.1.0-1) (2018-05-23) 354 | 355 | 356 | ### Features 357 | 358 | * splitChunks of vendors and commons ([5adc4e7](https://github.com/ansenhuang/fle-cli/commit/5adc4e7)) 359 | 360 | 361 | 362 | 363 | # [4.1.0-0](https://github.com/ansenhuang/fle-cli/compare/v4.0.0-beta.5...v4.1.0-0) (2018-05-22) 364 | 365 | 366 | ### Bug Fixes 367 | 368 | * optimize ([1c7ff5f](https://github.com/ansenhuang/fle-cli/commit/1c7ff5f)) 369 | 370 | 371 | ### Features 372 | 373 | * add fastclick in h5 ([03a8e09](https://github.com/ansenhuang/fle-cli/commit/03a8e09)) 374 | 375 | 376 | 377 | 378 | # [4.0.0-beta.5](https://github.com/ansenhuang/fle-cli/compare/v4.0.0-beta.4...v4.0.0-beta.5) (2018-05-21) 379 | 380 | 381 | ### Bug Fixes 382 | 383 | * remove module.exports when build es6 in browsers ([3c0e6e1](https://github.com/ansenhuang/fle-cli/commit/3c0e6e1)) 384 | 385 | 386 | 387 | 388 | # [4.0.0-beta.4](https://github.com/ansenhuang/fle-cli/compare/v4.0.0-beta.3...v4.0.0-beta.4) (2018-05-21) 389 | 390 | 391 | ### Bug Fixes 392 | 393 | * init lib of example ([89104a6](https://github.com/ansenhuang/fle-cli/commit/89104a6)) 394 | * lib compileType ([cd23f12](https://github.com/ansenhuang/fle-cli/commit/cd23f12)) 395 | 396 | 397 | 398 | 399 | # [4.0.0-beta.3](https://github.com/ansenhuang/fle-cli/compare/v3.10.11...v4.0.0-beta.3) (2018-05-21) 400 | 401 | 402 | ### Features 403 | 404 | * add babel plugin to module.exports ([98f3bd5](https://github.com/ansenhuang/fle-cli/commit/98f3bd5)) 405 | * add node boilerplate ([5ae037c](https://github.com/ansenhuang/fle-cli/commit/5ae037c)) 406 | * readme template ([5d08250](https://github.com/ansenhuang/fle-cli/commit/5d08250)) 407 | 408 | 409 | 410 | 411 | ## [3.10.11](https://github.com/ansenhuang/fle-cli/compare/v3.10.10...v3.10.11) (2018-05-14) 412 | 413 | 414 | ### Bug Fixes 415 | 416 | * css build autoprefixer ([27e5310](https://github.com/ansenhuang/fle-cli/commit/27e5310)) 417 | 418 | 419 | 420 | 421 | ## [3.10.10](https://github.com/ansenhuang/fle-cli/compare/v3.10.9...v3.10.10) (2018-05-11) 422 | 423 | 424 | ### Bug Fixes 425 | 426 | * browsers ([4a9e79e](https://github.com/ansenhuang/fle-cli/commit/4a9e79e)) 427 | 428 | 429 | 430 | 431 | ## [3.10.9](https://github.com/ansenhuang/fle-cli/compare/v3.10.8...v3.10.9) (2018-05-09) 432 | 433 | 434 | ### Bug Fixes 435 | 436 | * css rem ([441c94e](https://github.com/ansenhuang/fle-cli/commit/441c94e)) 437 | 438 | 439 | 440 | 441 | ## [3.10.8](https://github.com/ansenhuang/fle-cli/compare/v3.10.7...v3.10.8) (2018-05-02) 442 | 443 | 444 | 445 | 446 | ## [3.10.7](https://github.com/ansenhuang/fle-cli/compare/v3.10.6...v3.10.7) (2018-04-28) 447 | 448 | 449 | 450 | 451 | ## [3.10.6](https://github.com/ansenhuang/fle-cli/compare/v3.10.5...v3.10.6) (2018-04-26) 452 | 453 | 454 | ### Bug Fixes 455 | 456 | * * ([c24e161](https://github.com/ansenhuang/fle-cli/commit/c24e161)) 457 | * wenman pv&uv ([26e59b5](https://github.com/ansenhuang/fle-cli/commit/26e59b5)) 458 | 459 | 460 | 461 | 462 | ## [3.10.5](https://github.com/ansenhuang/fle-cli/compare/v3.10.4...v3.10.5) (2018-04-25) 463 | 464 | 465 | ### Bug Fixes 466 | 467 | * rem ([370003e](https://github.com/ansenhuang/fle-cli/commit/370003e)) 468 | * rollup vconsole ([cae681f](https://github.com/ansenhuang/fle-cli/commit/cae681f)) 469 | 470 | 471 | 472 | 473 | ## [3.10.4](https://github.com/ansenhuang/fle-cli/compare/v3.10.3...v3.10.4) (2018-04-24) 474 | 475 | 476 | 477 | 478 | ## [3.10.3](https://github.com/ansenhuang/fle-cli/compare/v3.10.2...v3.10.3) (2018-04-23) 479 | 480 | 481 | ### Bug Fixes 482 | 483 | * babel-cli presets & plugins ([3e3c727](https://github.com/ansenhuang/fle-cli/commit/3e3c727)) 484 | 485 | 486 | 487 | 488 | ## [3.10.2](https://github.com/ansenhuang/fle-cli/compare/v3.10.1...v3.10.2) (2018-04-23) 489 | 490 | 491 | ### Bug Fixes 492 | 493 | * lib export ([2aa9898](https://github.com/ansenhuang/fle-cli/commit/2aa9898)) 494 | 495 | 496 | 497 | 498 | ## [3.10.1](https://github.com/ansenhuang/fle-cli/compare/v3.10.0...v3.10.1) (2018-04-23) 499 | 500 | 501 | ### Bug Fixes 502 | 503 | * rollup modules ([0fb130a](https://github.com/ansenhuang/fle-cli/commit/0fb130a)) 504 | 505 | 506 | 507 | 508 | # [3.10.0](https://github.com/ansenhuang/fle-cli/compare/v3.9.3...v3.10.0) (2018-04-23) 509 | 510 | 511 | ### Features 512 | 513 | * babel-cli build lib ([df70a99](https://github.com/ansenhuang/fle-cli/commit/df70a99)) 514 | 515 | 516 | 517 | 518 | ## [3.9.3](https://github.com/ansenhuang/fle-cli/compare/v3.9.2...v3.9.3) (2018-04-19) 519 | 520 | 521 | ### Bug Fixes 522 | 523 | * vue js loader ([c37c5d5](https://github.com/ansenhuang/fle-cli/commit/c37c5d5)) 524 | 525 | 526 | 527 | 528 | ## [3.9.2](https://github.com/ansenhuang/fle-cli/compare/v3.9.1...v3.9.2) (2018-04-13) 529 | 530 | 531 | ### Bug Fixes 532 | 533 | * host,可以通过ip访问服务器 ([7c4042d](https://github.com/ansenhuang/fle-cli/commit/7c4042d)) 534 | 535 | 536 | 537 | 538 | ## [3.9.1](https://github.com/ansenhuang/fle-cli/compare/v3.9.0...v3.9.1) (2018-04-11) 539 | 540 | 541 | 542 | 543 | # [3.9.0](https://github.com/ansenhuang/fle-cli/compare/v3.8.1...v3.9.0) (2018-04-03) 544 | 545 | 546 | ### Features 547 | 548 | * add create page and html template ([adec2e0](https://github.com/ansenhuang/fle-cli/commit/adec2e0)) 549 | 550 | 551 | 552 | 553 | ## [3.8.1](https://github.com/ansenhuang/fle-cli/compare/v3.8.0...v3.8.1) (2018-04-02) 554 | 555 | 556 | 557 | 558 | # [3.8.0](https://github.com/ansenhuang/fle-cli/compare/v3.7.10...v3.8.0) (2018-04-02) 559 | 560 | 561 | 562 | 563 | ## [3.7.10](https://github.com/ansenhuang/fle-cli/compare/v3.7.9...v3.7.10) (2018-03-29) 564 | 565 | 566 | ### Bug Fixes 567 | 568 | * px2rem ([9a49128](https://github.com/ansenhuang/fle-cli/commit/9a49128)) 569 | 570 | 571 | 572 | 573 | ## [3.7.9](https://github.com/ansenhuang/fle-cli/compare/v3.7.8...v3.7.9) (2018-03-25) 574 | 575 | 576 | ### Bug Fixes 577 | 578 | * rollup css modules ([e60c287](https://github.com/ansenhuang/fle-cli/commit/e60c287)) 579 | 580 | 581 | 582 | 583 | ## [3.7.8](https://github.com/ansenhuang/fle-cli/compare/v3.7.7...v3.7.8) (2018-03-24) 584 | 585 | 586 | ### Bug Fixes 587 | 588 | * rollup build ([914863a](https://github.com/ansenhuang/fle-cli/commit/914863a)) 589 | 590 | 591 | 592 | 593 | ## [3.7.7](https://github.com/ansenhuang/fle-cli/compare/v3.7.6...v3.7.7) (2018-03-24) 594 | 595 | 596 | ### Bug Fixes 597 | 598 | * add helpers for rollup lib ([3b2555e](https://github.com/ansenhuang/fle-cli/commit/3b2555e)) 599 | 600 | 601 | 602 | 603 | ## [3.7.6](https://github.com/ansenhuang/fle-cli/compare/v3.7.5...v3.7.6) (2018-03-21) 604 | 605 | 606 | ### Bug Fixes 607 | 608 | * boilerplate vue ([96b55a5](https://github.com/ansenhuang/fle-cli/commit/96b55a5)) 609 | 610 | 611 | 612 | 613 | ## [3.7.5](https://github.com/ansenhuang/fle-cli/compare/v3.7.3...v3.7.5) (2018-03-21) 614 | 615 | 616 | ### Bug Fixes 617 | 618 | * spawn eacces ([e6e81b6](https://github.com/ansenhuang/fle-cli/commit/e6e81b6)) 619 | 620 | 621 | 622 | 623 | ## [3.7.3](https://github.com/ansenhuang/fle-cli/compare/v3.7.2...v3.7.3) (2018-03-17) 624 | 625 | 626 | 627 | 628 | ## [3.7.2](https://github.com/ansenhuang/fle-cli/compare/v3.7.1...v3.7.2) (2018-03-17) 629 | 630 | 631 | ### Bug Fixes 632 | 633 | * upload config log ([b27a0c5](https://github.com/ansenhuang/fle-cli/commit/b27a0c5)) 634 | 635 | 636 | ### Features 637 | 638 | * 增加dev和build的单独打包功能 ([626dab7](https://github.com/ansenhuang/fle-cli/commit/626dab7)) 639 | 640 | 641 | 642 | 643 | ## [3.7.1](https://github.com/ansenhuang/fle-cli/compare/v3.7.0...v3.7.1) (2018-03-16) 644 | 645 | 646 | ### Bug Fixes 647 | 648 | * upload build config ([5adf877](https://github.com/ansenhuang/fle-cli/commit/5adf877)) 649 | 650 | 651 | 652 | 653 | # [3.7.0](https://github.com/ansenhuang/fle-cli/compare/v3.5.0...v3.7.0) (2018-03-16) 654 | 655 | 656 | 657 | 658 | # [3.5.0](https://github.com/ansenhuang/fle-cli/compare/bbb933d...v3.5.0) (2018-03-14) 659 | 660 | 661 | ### Bug Fixes 662 | 663 | * babel、eslint自定义 ([f33d8c4](https://github.com/ansenhuang/fle-cli/commit/f33d8c4)) 664 | * boilerplate ([bbb933d](https://github.com/ansenhuang/fle-cli/commit/bbb933d)) 665 | * init install ([9bb07f9](https://github.com/ansenhuang/fle-cli/commit/9bb07f9)) 666 | * init yarn ([41b2c16](https://github.com/ansenhuang/fle-cli/commit/41b2c16)) 667 | * loader resolve ([b652bc8](https://github.com/ansenhuang/fle-cli/commit/b652bc8)) 668 | * rollup name ([451e94a](https://github.com/ansenhuang/fle-cli/commit/451e94a)) 669 | * vendor ([13c0383](https://github.com/ansenhuang/fle-cli/commit/13c0383)) 670 | * webpack ([14fe835](https://github.com/ansenhuang/fle-cli/commit/14fe835)) 671 | 672 | 673 | ### Features 674 | 675 | * define vendor chunks ([db61171](https://github.com/ansenhuang/fle-cli/commit/db61171)) 676 | * dev dll ([d7cefc9](https://github.com/ansenhuang/fle-cli/commit/d7cefc9)) 677 | * imagemin ([becbdff](https://github.com/ansenhuang/fle-cli/commit/becbdff)) 678 | * rem layout ([52945c4](https://github.com/ansenhuang/fle-cli/commit/52945c4)) 679 | * 优化babel、uglifyjs ([fdbdf7c](https://github.com/ansenhuang/fle-cli/commit/fdbdf7c)) 680 | * 增加cdn上传功能 ([48ad458](https://github.com/ansenhuang/fle-cli/commit/48ad458)) 681 | 682 | 683 | 684 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 fle-cli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fle-cli 2 | 3 | [![npm package](https://img.shields.io/npm/v/fle-cli.svg?style=flat-square)](https://www.npmjs.org/package/fle-cli) 4 | [![NPM downloads](http://img.shields.io/npm/dt/fle-cli.svg?style=flat-square)](https://npmjs.org/package/fle-cli) 5 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ansenhuang/fle-cli/blob/master/LICENSE) 6 | 7 | A command line tool for front-end developer with zero configuration. It aims to improve efficiency and make workflow easily. 8 | 9 | Just install once and you will get all the following features. 10 | 11 | ## Features 12 | 13 | * Support multiple boilerplate (react, vue, ...) 14 | * Support javascript library (es6, iife, commonjs, ...) 15 | * Support upload files in compile 16 | * Support phone debug in development 17 | * Powerful postcss plugin with css modules 18 | * flexible code split by default with webpack4+ 19 | * standard code style with eslint 20 | * optimize image in compile if necessary 21 | * Build-in rem layout solution for H5 22 | * freemarker for Java template (ftl) 23 | * ... 24 | 25 | ## Installation 26 | 27 | ```bash 28 | $ npm install fle-cli -g 29 | ``` 30 | 31 | or use yarn 32 | 33 | ```bash 34 | $ yarn global add fle-cli 35 | ``` 36 | 37 | ## Quick Start 38 | 39 | ### Init a project 40 | 41 | ```bash 42 | $ fle init 43 | ``` 44 | 45 | ### Development 46 | 47 | ```bash 48 | $ fle dev 49 | ``` 50 | 51 | ### Production 52 | 53 | ```bash 54 | $ fle build 55 | ``` 56 | 57 | ### Help 58 | 59 | ```bash 60 | $ fle -h 61 | ``` 62 | 63 | ## Docs 64 | 65 | For more details, please go to [https://ansenhuang.github.io/docs/fle-cli/zh-cn/](https://ansenhuang.github.io/docs/fle-cli/zh-cn/). 66 | 67 | ## Changelog 68 | 69 | [Changelog](https://github.com/ansenhuang/fle-cli/blob/master/CHANGELOG.md) 70 | 71 | ## License 72 | 73 | [MIT](https://tldrlegal.com/license/mit-license) 74 | -------------------------------------------------------------------------------- /bin/fle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var fs = require('fs'); 6 | var path = require('path'); 7 | var program = require('commander'); 8 | var spawn = require('cross-spawn'); 9 | var updateNotifier = require('update-notifier'); 10 | var color = require('@fle/color'); 11 | 12 | var { 13 | pkgName, 14 | pkgVersion, 15 | fleHomePath, 16 | needVerifyCommands 17 | } = require('../lib/consts'); 18 | var { checkProject } = require('../lib/utils'); 19 | 20 | // 检查更新 21 | updateNotifier({ 22 | pkg: { 23 | name: pkgName, 24 | version: pkgVersion 25 | }, 26 | updateCheckInterval: 86400000 // 每天检查一次 27 | }).notify({ 28 | isGlobal: true 29 | }); 30 | 31 | // 第一次启动需要安装编译需要的依赖 32 | var buildPkgPath = path.join(fleHomePath, 'package.json'); 33 | if (!fs.existsSync(buildPkgPath) || require(buildPkgPath)['fle-version'] !== pkgVersion) { 34 | require('../lib/install'); 35 | require('../lib/fix/babel-cli'); 36 | } 37 | 38 | program 39 | .version(pkgVersion, '-v, --version') 40 | .usage(' [options]') 41 | .on('--help', () => { 42 | console.log(); 43 | console.log(' Commands:'); 44 | console.log(); 45 | console.log(' init 创建项目工程或页面'); 46 | console.log(' dev 启动本地开发调试'); 47 | console.log(' build 编译生产环境代码'); 48 | console.log(' lib 编译js库工程'); 49 | console.log(' upload 上传图片或文件'); 50 | console.log(' sprite 将多张图片合成雪碧图'); 51 | console.log(); 52 | }) 53 | .parse(process.argv); 54 | 55 | var subcmd = program.args[0]; 56 | var aliases = { 57 | "i": "init", 58 | "d": "dev", 59 | "b": "build", 60 | "l": "lib", 61 | "u": "upload" 62 | }; 63 | 64 | if (aliases[subcmd]) { 65 | subcmd = aliases[subcmd]; 66 | } 67 | 68 | if (!subcmd || subcmd === 'help') { 69 | program.help(); 70 | } else { 71 | if (needVerifyCommands.indexOf(subcmd) !== -1) { 72 | checkProject(); 73 | } 74 | 75 | var file = path.join(__dirname, `../lib/commands/${subcmd}.js`); 76 | 77 | fs.stat(file, (err) => { 78 | if (err) { 79 | console.log(`\n不存在此命令:${color.cyan(subcmd)}\n`); 80 | process.exit(1); 81 | } 82 | 83 | spawn('node', [file].concat(process.argv.slice(3)), { stdio: 'inherit' }); 84 | }); 85 | } 86 | -------------------------------------------------------------------------------- /boilerplate/app/.gitignore.keep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .cache/ 3 | .vscode/ 4 | node_modules/ 5 | /lib 6 | /dist 7 | /public 8 | *.log* 9 | -------------------------------------------------------------------------------- /boilerplate/app/README.md: -------------------------------------------------------------------------------- 1 | # 项目名称 2 | 3 | **【】中的内容需要自己填写,并删除本行** 4 | 5 | 【项目简介】 6 | 7 | ## 如何运行 8 | 9 | > node版本 `>=6.11.5` 10 | 11 | ### 环境配置 12 | 13 | #### 安装全局编译工具 14 | 15 | ``` bash 16 | $ npm install -g fle-cli 17 | 18 | # yarn 19 | $ yarn global add fle-cli 20 | ``` 21 | 22 | 【其他说明】 23 | 24 | ### 开发过程 25 | 26 | #### 命令 27 | 28 | ```bash 29 | # 本地开发 30 | fle dev 31 | 32 | # 代码构建 33 | fle build 34 | ``` 35 | 36 | 查看更多说明: [构建文档](https://www.npmjs.com/package/fle-cli) 37 | 38 | #### 代理配置 39 | 40 | | 本地地址 | 代理地址 | 41 | |---------|--------| 42 | | 【`/api/*`】 | 【`http://xxx`】 | 43 | 44 | ### 线上发布 45 | 46 | 【发布说明】 47 | 48 | ### 项目维护 49 | 50 | | 角色 | 人员 | 51 | |---------|----------| 52 | | 前端开发 | 【xxx】、【yyy】 | 53 | | 后端开发 | 【xxx】 | 54 | | 产品经理 | 【xxx】 | 55 | | 交互设计 | 【xxx】 | 56 | 57 | ### 其他说明 58 | 59 | * 【[数据上报](http://xxx)】 60 | * 【[需求文档](http://xxx)】 61 | * 【[设计稿](http://xxx)】 62 | 63 | ## 业务介绍 64 | 65 | 【业务描述】 66 | 67 | ### 业务入口 68 | 69 | * 【AAA】 70 | * 【BBB】 71 | * 【CCC】 72 | 73 | 【补充说明】 74 | 75 | ### 页面信息 76 | 77 | |页面目录|页面描述|页面链接|参数描述| 78 | |-------|------|-------|-------| 79 | |【index】 | 【首页】 | 【[https://xxx.com](https://xxx.com/)】 | 无 | 80 | 81 | ## 其他事项 82 | 83 | 补充说明 84 | 85 | > 【项目备注】 86 | -------------------------------------------------------------------------------- /boilerplate/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fle-boilerplate-app", 3 | "version": "0.0.0", 4 | "description": "A app project created by fle-cli.", 5 | "keywords": ["fle", "webpack", "javascript"], 6 | "author": "huangancheng", 7 | "license": "MIT", 8 | "dependencies": {} 9 | } 10 | -------------------------------------------------------------------------------- /boilerplate/app/src/example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "示例", 3 | "keyswords": "", 4 | "description": "", 5 | "icon": "", 6 | "template": "/default.html", 7 | "compiled": true 8 | } 9 | -------------------------------------------------------------------------------- /boilerplate/app/src/example/hello/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansenhuang/fle-cli/96ede8e95c5b4f582946f44de9e667aeea1598cb/boilerplate/app/src/example/hello/images/logo.png -------------------------------------------------------------------------------- /boilerplate/app/src/example/hello/index.js: -------------------------------------------------------------------------------- 1 | import $style from './style.module.css' 2 | 3 | const appNode = document.createElement('div') 4 | appNode.className = $style.app 5 | 6 | appNode.innerHTML = ` 7 |
8 | logo 9 |

Welcome

10 |
11 |

12 | To get started, edit index.js and save to reload. 13 |

14 | ` 15 | 16 | export default appNode 17 | -------------------------------------------------------------------------------- /boilerplate/app/src/example/hello/style.module.css: -------------------------------------------------------------------------------- 1 | .app { 2 | text-align: center; 3 | } 4 | 5 | .logo { 6 | height: 80px; 7 | } 8 | 9 | .header { 10 | background-color: #222; 11 | height: 150px; 12 | padding: 20px; 13 | color: white; 14 | } 15 | 16 | .title { 17 | font-size: 1.5em; 18 | } 19 | 20 | .intro { 21 | font-size: large; 22 | } 23 | -------------------------------------------------------------------------------- /boilerplate/app/src/example/index.js: -------------------------------------------------------------------------------- 1 | import hello from './hello' 2 | 3 | document.getElementById('root').appendChild(hello) 4 | -------------------------------------------------------------------------------- /boilerplate/lib/.gitignore.keep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .cache/ 3 | .vscode/ 4 | node_modules/ 5 | /lib 6 | /dist 7 | *.log* 8 | -------------------------------------------------------------------------------- /boilerplate/lib/.npmignore.keep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .cache/ 3 | .vscode/ 4 | node_modules/ 5 | /dist 6 | /src 7 | /fle.json 8 | *.log* 9 | -------------------------------------------------------------------------------- /boilerplate/lib/README.md: -------------------------------------------------------------------------------- 1 | # 项目名称 2 | 3 | **【】中的内容需要自己填写,并删除本行** 4 | 5 | 【项目简介】 6 | 7 | ## 开始安装 8 | 9 | 【安装说明】 10 | 11 | ## 如何使用 12 | 13 | 【使用说明】 14 | 15 | ## API 16 | 17 | 【API说明】 18 | 19 | ## 环境配置 20 | 21 | 构建工具 22 | 23 | ``` bash 24 | $ npm install -g fle-cli 25 | 26 | # yarn 27 | $ yarn global add fle-cli 28 | ``` 29 | 30 | 命令说明 31 | 32 | ```bash 33 | # 本地开发 34 | fle dev 35 | 36 | # 代码构建 37 | fle build 38 | ``` 39 | 40 | 查看更多说明: [构建文档](https://www.npmjs.com/package/fle-cli) 41 | 42 | ## 补充说明 43 | 44 | 【备注】 45 | -------------------------------------------------------------------------------- /boilerplate/lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fle-boilerplate-lib", 3 | "version": "0.0.0", 4 | "description": "A library project created by fle-cli.", 5 | "main": "lib/index.js", 6 | "keywords": [], 7 | "author": "huangancheng", 8 | "license": "MIT", 9 | "dependencies": {} 10 | } 11 | -------------------------------------------------------------------------------- /boilerplate/lib/src/common/index.js: -------------------------------------------------------------------------------- 1 | export default function formatDate (date = new Date(), fmt = 'yyyy-MM-dd hh:mm:ss') { 2 | let o = { 3 | MM: date.getMonth() + 1, 4 | dd: date.getDate(), 5 | hh: date.getHours(), 6 | mm: date.getMinutes(), 7 | ss: date.getSeconds() 8 | } 9 | 10 | fmt = fmt.replace('yyyy', date.getFullYear()) 11 | 12 | Object.keys(o).forEach(k => { 13 | fmt = fmt.replace(k, o[k] > 9 ? o[k] : '0' + o[k]) 14 | }) 15 | 16 | return fmt 17 | } 18 | -------------------------------------------------------------------------------- /boilerplate/lib/src/example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "示例", 3 | "keyswords": "", 4 | "description": "", 5 | "icon": "/favicon.ico", 6 | "template": "src/example/index.html", 7 | "compiled": true 8 | } 9 | -------------------------------------------------------------------------------- /boilerplate/lib/src/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 | 9 | <% if (htmlWebpackPlugin.options.icon) { %> 10 | 11 | <% } %> 12 | <% for (var i = 0; i < htmlWebpackPlugin.options.css.length; i++) { %> 13 | 14 | <% } %> 15 | <% for (var j = 0; j < htmlWebpackPlugin.options.prejs.length; j++) { %> 16 | 17 | <% } %> 18 | 19 | 20 |
21 | <% for (var k = 0; k < htmlWebpackPlugin.options.js.length; k++) { %> 22 | 23 | <% } %> 24 | 25 | 26 | -------------------------------------------------------------------------------- /boilerplate/lib/src/example/index.js: -------------------------------------------------------------------------------- 1 | import module from '@/common' 2 | import './style.css' 3 | 4 | // run module 5 | module() 6 | 7 | document.getElementById('root').innerHTML = [ 8 | `

Hello, fle-cli.

`, 9 | `

Date: ${module()}

` 10 | ].join('') 11 | -------------------------------------------------------------------------------- /boilerplate/lib/src/example/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #ccc; 3 | } 4 | -------------------------------------------------------------------------------- /boilerplate/miniprogram/.gitignore.keep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.log 4 | *yarn* 5 | *.lock -------------------------------------------------------------------------------- /boilerplate/miniprogram/README.md: -------------------------------------------------------------------------------- 1 | # 小程序 2 | 3 | ### 目录结构 4 | 5 | root 6 | |----components/常用组件 7 | |----deps/ 常用依赖包引入 8 | |----assets/ 图片等资源文件,不过建议之后添加的图片放入子包目录 9 | |----model/ 数据模型文件 10 | |----utils 常用方法文件 11 | |----pages/ 主包页面文件 12 | |----packageA/ 子包文件 13 | |----packageB/ 子包文件 14 | |----packageC/ 子包文件 15 | 16 | 17 | 18 | ### 开发说明 19 | 20 | #### 统一请求出口 21 | 22 | * `model/fetchAPI.js`定义了统一的数据请求接口,reqwest(普通数据请求)、uploadFile(文件上传) 23 | * 开发过程中把数据源定为测试环境、提交审核之前记得将数据源改为线上; 24 | 25 | #### 常用方法 26 | 27 | * `utils/format.js` 封装时间格式化方法 28 | * `utils/utils.js` 封装常用的方法,第三方登录,formId上报等; 29 | * `utils/wxAPI.js` 微信提供的常用api Promise化封装方法 30 | 31 | ### 注意事项 32 | 33 | * pages放主入口相关页面,packageA,packageB,packageC放次要加载页面 34 | * 页面参数不需要encode,否则解析不出来 35 | 36 | -------------------------------------------------------------------------------- /boilerplate/miniprogram/app.js: -------------------------------------------------------------------------------- 1 | import DATracker from './utils/DATracker' 2 | import fundebug from './deps/fundebug.1.0.0.min.js' 3 | 4 | App({ 5 | onLaunch: function () { 6 | // 请填入哈勃的appKey 7 | // DATracker.init('key') 8 | // 用于错误检测,apikey会过期 9 | // fundebug.init({ 10 | // apikey : '5bbf66eaa6cd39ec26714e1d2ee619f452a804438c4d029b673db8b3eca150a8' 11 | // }) 12 | wx.getSystemInfo({ 13 | success: (res) => { 14 | this.globalData.systemInfo = res; 15 | console.log(res) 16 | } 17 | }) 18 | }, 19 | globalData: { 20 | userInfo: null 21 | } 22 | }) -------------------------------------------------------------------------------- /boilerplate/miniprogram/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages":[ 3 | "pages/index/index" 4 | ], 5 | "window":{ 6 | "backgroundTextStyle":"light", 7 | "navigationBarBackgroundColor": "#fff", 8 | "navigationBarTitleText": "WeChat", 9 | "navigationBarTextStyle":"black" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /boilerplate/miniprogram/app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .container { 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | justify-content: space-between; 8 | padding: 200rpx 0; 9 | box-sizing: border-box; 10 | } 11 | -------------------------------------------------------------------------------- /boilerplate/miniprogram/deps/uuid.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;n="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,n.uuidv1=e()}}(function(){return function e(n,r,o){function t(u,f){if(!r[u]){if(!n[u]){var s="function"==typeof require&&require;if(!f&&s)return s(u,!0);if(i)return i(u,!0);var d=new Error("Cannot find module '"+u+"'");throw d.code="MODULE_NOT_FOUND",d}var a=r[u]={exports:{}};n[u][0].call(a.exports,function(e){var r=n[u][1][e];return t(r?r:e)},a,a.exports,e,n,r,o)}return r[u].exports}for(var i="function"==typeof require&&require,u=0;u>>((3&n)<<3)&255;return i}}},{}],3:[function(e,n,r){function o(e,n,r){var o=n&&r||0,a=n||[];e=e||{};var c=e.node||t,l=void 0!==e.clockseq?e.clockseq:i;if(null==c||null==l){var p=u();null==c&&(c=t=[1|p[0],p[1],p[2],p[3],p[4],p[5]]),null==l&&(l=i=16383&(p[6]<<8|p[7]))}var v=void 0!==e.msecs?e.msecs:(new Date).getTime(),y=void 0!==e.nsecs?e.nsecs:d+1,m=v-s+(y-d)/1e4;if(m<0&&void 0===e.clockseq&&(l=l+1&16383),(m<0||v>s)&&void 0===e.nsecs&&(y=0),y>=1e4)throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");s=v,d=y,i=l,v+=122192928e5;var w=(1e4*(268435455&v)+y)%4294967296;a[o++]=w>>>24&255,a[o++]=w>>>16&255,a[o++]=w>>>8&255,a[o++]=255&w;var b=v/4294967296*1e4&268435455;a[o++]=b>>>8&255,a[o++]=255&b,a[o++]=b>>>24&15|16,a[o++]=b>>>16&255,a[o++]=l>>>8|128,a[o++]=255&l;for(var g=0;g<6;++g)a[o+g]=c[g];return n?n:f(a)}var t,i,u=e("./lib/rng"),f=e("./lib/bytesToUuid"),s=0,d=0;n.exports=o},{"./lib/bytesToUuid":1,"./lib/rng":2}]},{},[3])(3)}); -------------------------------------------------------------------------------- /boilerplate/miniprogram/model/fetchAPI.js: -------------------------------------------------------------------------------- 1 | import wxAPI from '../utils/wxAPI'; 2 | import { 3 | getXUserAgent, 4 | } from '../utils/utils' 5 | import config from '../utils/config' 6 | 7 | const domain = `https://${config.host}`; 8 | 9 | export const getCurrentPageUrl = function () { 10 | var pages = getCurrentPages() 11 | var currentPage = pages[pages.length - 1] 12 | var url = currentPage.route 13 | 14 | return url 15 | } 16 | 17 | //获取小程序的协议header中所需的X-User-Agent,同时生成并存储设备ID 18 | export const getXUserAgent = function () { 19 | let xUserAgent = wx.getStorageSync('xUserAgent'); 20 | if (!xUserAgent) { 21 | const systemInfo = getApp().globalData.systemInfo; 22 | let deviceId = wx.getStorageSync('deviceId'); 23 | if (!deviceId) { 24 | deviceId = uuidv1(); 25 | wx.setStorageSync('deviceId', deviceId); 26 | } 27 | xUserAgent = `cpminiprogram/${config.clientVersion}/${config.protocolVersion} (${deviceId};${systemInfo.model};${systemInfo.screenHeight}x${systemInfo.screenWidth}) (${(systemInfo.system).replace(' ', ';')}) (miniprogram)` 28 | wx.setStorageSync('xUserAgent', xUserAgent); 29 | } 30 | return xUserAgent; 31 | } 32 | 33 | /*** 34 | * 数据请求方法 35 | * @param options object类型 36 | * url:必填,请求链接 37 | * data:请求数据object类型,可为空 38 | * method:"GET" or "POST" 39 | *header:object类型 40 | * @returns {*}返回Promise 41 | */ 42 | export const reqwest = function (options = {}) { 43 | 44 | const wxRequest = wxAPI.wxRequest(); 45 | return wxRequest({ 46 | url: domain + options.url, 47 | data: options.data, 48 | method: options.method || 'GET', 49 | dataType: options.dataType, 50 | header: { 51 | "X-User-Agent": getXUserAgent(), 52 | "X-Auth-Token": wx.getStorageSync('authToken') || '', 53 | "X-NO-CSRF": true, 54 | ...options.header 55 | } 56 | }).then((res) => { 57 | return Promise.resolve(res.data) 58 | }, (res) => { 59 | if (res.statusCode === 401) { 60 | wx.showToast({ 61 | title: '登录已过期,请重新登录', 62 | icon: 'none' 63 | }) 64 | // 跳转到项目的登录页面 65 | // wx.navigateTo({ 66 | // url: `/pages/login/login?targetUrl=/${encodeURIComponent(getCurrentPageUrl())}` 67 | // }) 68 | } 69 | return Promise.reject(res.data) 70 | }) 71 | } 72 | 73 | export const uploadFile = function (options = {}) { 74 | return wxAPI.wxUploadFile({ 75 | url: domain + options.url, 76 | filePath: options.filePath, 77 | name: options.name, 78 | formData: options.formData || {}, 79 | header: options.header || { 80 | "X-Authorization": wx.getStorageSync('token') || '' 81 | } 82 | }).then((res) => { 83 | return Promise.resolve(JSON.parse(res.data)) 84 | }, (res) => { 85 | return Promise.reject(JSON.parse(res.data)) 86 | }) 87 | } -------------------------------------------------------------------------------- /boilerplate/miniprogram/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fle-boilerplate-miniprogram", 3 | "version": "0.0.0", 4 | "description": "A miniprogram project created by fle-cli.", 5 | "keywords": ["fle", "webpack", "miniprogram"], 6 | "author": "huangancheng", 7 | "license": "MIT", 8 | "dependencies": { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /boilerplate/miniprogram/pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | const app = getApp() 4 | 5 | Page({ 6 | data: {}, 7 | onLoad: function () {}, 8 | }) 9 | -------------------------------------------------------------------------------- /boilerplate/miniprogram/pages/index/index.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /boilerplate/miniprogram/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | hello world 4 | 5 | -------------------------------------------------------------------------------- /boilerplate/miniprogram/pages/index/index.wxss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansenhuang/fle-cli/96ede8e95c5b4f582946f44de9e667aeea1598cb/boilerplate/miniprogram/pages/index/index.wxss -------------------------------------------------------------------------------- /boilerplate/miniprogram/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true 12 | }, 13 | "compileType": "miniprogram", 14 | "libVersion": "2.3.0", 15 | "appid": "wx7a095676ef39b8bc", 16 | "projectname": "aa", 17 | "debugOptions": { 18 | "hidedInDevtools": [] 19 | }, 20 | "isGameTourist": false, 21 | "condition": { 22 | "search": { 23 | "current": -1, 24 | "list": [] 25 | }, 26 | "conversation": { 27 | "current": -1, 28 | "list": [] 29 | }, 30 | "game": { 31 | "currentL": -1, 32 | "list": [] 33 | }, 34 | "miniprogram": { 35 | "current": -1, 36 | "list": [] 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /boilerplate/miniprogram/utils/DATracker.js: -------------------------------------------------------------------------------- 1 | var ArrayProto=Array.prototype,FuncProto=Function.prototype,ObjProto=Object.prototype,slice=ArrayProto.slice,toString=ObjProto.toString,hasOwnProperty=ObjProto.hasOwnProperty;var nativeForEach=ArrayProto.forEach,nativeIndexOf=ArrayProto.indexOf,nativeIsArray=Array.isArray,breaker={};var _={};if(!Array.indexOf){Array.prototype.indexOf=function(el){for(var i=0,n=this.length;i>18&63;h2=bits>>12&63;h3=bits>>6&63;h4=bits&63;tmp_arr[ac++]=b64.charAt(h1)+b64.charAt(h2)+b64.charAt(h3)+b64.charAt(h4)}while(i127)&&(c1<2048)){enc=String.fromCharCode((c1>>6)|192,(c1&63)|128)}else{enc=String.fromCharCode((c1>>12)|224,((c1>>6)&63)|128,(c1&63)|128)}}if(enc!==null){if(end>start){utftext+=string.substring(start,end)}utftext+=enc;start=end=n+1}}if(end>start){utftext+=string.substring(start,string.length)}return utftext};_.sha1=function(str){var hexcase=0;var b64pad="";var chrsz=8;function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length*chrsz))}function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length*chrsz))}function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length*chrsz))}function hex_hmac_sha1(key,data){return binb2hex(core_hmac_sha1(key,data))}function b64_hmac_sha1(key,data){return binb2b64(core_hmac_sha1(key,data))}function str_hmac_sha1(key,data){return binb2str(core_hmac_sha1(key,data))}function sha1_vm_test(){return hex_sha1("abc")=="a9993e364706816aba3e25717850c26c9cd0d89d"}function core_sha1(x,len){x[len>>5]|=128<<(24-len%32);x[((len+64>>9)<<4)+15]=len;var w=Array(80);var a=1732584193;var b=-271733879;var c=-1732584194;var d=271733878;var e=-1009589776;for(var i=0;i16){bkey=core_sha1(bkey,key.length*chrsz)}var ipad=Array(16),opad=Array(16);for(var i=0;i<16;i++){ipad[i]=bkey[i]^909522486;opad[i]=bkey[i]^1549556828}var hash=core_sha1(ipad.concat(str2binb(data)),512+data.length*chrsz);return core_sha1(opad.concat(hash),512+160)}function safe_add(x,y){var lsw=(x&65535)+(y&65535);var msw=(x>>16)+(y>>16)+(lsw>>16);return(msw<<16)|(lsw&65535)}function rol(num,cnt){return(num<>>(32-cnt))}function str2binb(str){var bin=Array();var mask=(1<>5]|=(str.charCodeAt(i/chrsz)&mask)<<(24-i%32)}return bin}function binb2str(bin){var str="";var mask=(1<>5]>>>(24-i%32))&mask)}return str}function binb2hex(binarray){var hex_tab=hexcase?"0123456789ABCDEF":"0123456789abcdef";var str="";for(var i=0;i>2]>>((3-i%4)*8+4))&15)+hex_tab.charAt((binarray[i>>2]>>((3-i%4)*8))&15)}return str}function binb2b64(binarray){var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var str="";for(var i=0;i>2]>>8*(3-i%4))&255)<<16)|(((binarray[i+1>>2]>>8*(3-(i+1)%4))&255)<<8)|((binarray[i+2>>2]>>8*(3-(i+2)%4))&255);for(var j=0;j<4;j++){if(i*8+j*6>binarray.length*32){str+=b64pad}else{str+=tab.charAt((triplet>>6*(3-j))&63)}}}return str}return hex_sha1(str)};_.UUID=(function(){var callback=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=Math.random()*16|0,v=c=="x"?r:(r&3|8);return v.toString(16)})};return callback})();_.HTTPBuildQuery=function(formdata,arg_separator){var use_val,use_key,tmp_arr=[];if(_.isUndefined(arg_separator)){arg_separator="&"}_.each(formdata,function(val,key){use_val=encodeURIComponent(val.toString());use_key=encodeURIComponent(key);tmp_arr[tmp_arr.length]=use_key+"="+use_val});return tmp_arr.join(arg_separator)};_.isJSONString=function(str){try{JSON.parse(str)}catch(e){return false}return true};_.localStorage={setStorage:function(){},getStorage:function(){return wx.getStorageSync("DATracker_wechat")||""},_state:{},toState:function(t){var e=null;_.isJSONString(t)?(e=JSON.parse(t),e.deviceUdid?this._state=e:this.set("deviceUdid",_.UUID())):this.set("deviceUdid",_.UUID())},set:function(t,e){this._state=this._state||{};this._state[t]=e;return this.save()},get:function(t){return this._state[t]||""},save:function(){var saveComplete={isOk:true,errorMsg:""};try{var str=JSON.stringify(this._state);wx.setStorageSync("DATracker_wechat",str);if(str!==this.getStorage()){saveComplete.isOk=false;saveComplete.errorMsg="保存后,重新获取不一致"}}catch(error){saveComplete.isOk=false;saveComplete.errorMsg=error}return saveComplete},init:function(){var t=this.getStorage();t?this.toState(t):this.set("deviceUdid",_.UUID())}};_.console=function(){if("object"==typeof console&&console.log){try{return console.log.apply(console,arguments)}catch(t){console.log(arguments[0])}}};_.info={callback:function(){},properties:{},getSystem:function(){var self=this;var properties=self.properties;function getNetWork(){wx.getNetworkType({success:function(res){properties.networkType=res.networkType},complete:other})}function other(){wx.getSystemInfo({success:function(res){properties.deviceModel=res.model;properties.screenWidth=Number(res.windowWidth);properties.screenHeight=Number(res.windowHeight);properties.deviceOs=res.system.split(" ")[0];properties.deviceOsVersion=res.system.split(" ")[1],properties.devicePlatform=res.platform;properties.weixinVersion=res.version;properties.localeLanguage=res.language},complete:self.setStatusComplete.bind(self)})}getNetWork()},setStatusComplete:function(){_.localStorage.set("deviceProperties",this.properties);this.callback(this.properties)}}; 3 | 4 | 5 | var lLIBVERSION = '1.1.1'; 6 | var SDKTYPE = 'MiniProgram'; 7 | 8 | _.localStorage.init(); 9 | 10 | function on(obj, event, callFn) { 11 | if(obj[event]) { 12 | var fn = obj[event]; 13 | obj[event] = function(obj) { 14 | callFn.call(this, obj, event); 15 | fn.call(this, obj); 16 | }; 17 | } else { 18 | obj[event] = function(obj) { 19 | callFn.call(this, obj, event); 20 | }; 21 | } 22 | } 23 | 24 | //默认事件类型 25 | var DATATYPE = 'e'; 26 | /** 27 | * 内置事件 28 | */ 29 | var DEFAULTEVENTID = { 30 | //表示会话开始事件 31 | 'da_session_start': { 32 | 'dataType': 'ie' 33 | }, 34 | //表示会话结束事件 35 | 'da_session_close': { 36 | 'dataType': 'ie' 37 | }, 38 | //通过用户登陆传入的 userId 信息来映射设备 ID, 用户登出事件 39 | 'da_u_login': { 40 | 'dataType': 'ie' 41 | }, 42 | //用户登录事件 43 | 'da_u_logout': { 44 | 'dataType': 'ie' 45 | }, 46 | //用户 ID 关联 绑定输入的 newUserId 和已有 userID,用户注册等同一用户 userId 变动场景。 47 | 'da_u_signup': { 48 | 'dataType': 'ie' 49 | }, 50 | //用户属性设置内部事件 51 | 'da_user_profile': { 52 | 'dataType': 'ie' 53 | }, 54 | //页面浏览事件,浏览是一大类用户交互集合,设计特定 dataType = “pv” 55 | 'da_screen': { 56 | 'dataType': 'pv' 57 | }, 58 | //应用激活事件,应用第一次打开时发送 59 | 'da_activate': { 60 | 'dataType': 'ie' 61 | }, 62 | // 发送数据异常错误 63 | 'da_send_error': { 64 | 'dataType': 'ie' 65 | } 66 | }; 67 | /** 68 | * 开发约定: 对外 api 格式 : mm_dd_ww() 69 | * 内部api 格式 : mmDdWw() 70 | * 71 | */ 72 | var DATracker = { 73 | config: { 74 | apiHost: 'https://hubble.netease.com', 75 | appKey: '', 76 | userId: '', 77 | sessionStartTime: '', 78 | persistedTime: '', 79 | //最后一次触发事件,事件名称和触发时间 80 | lastEvent: { 81 | eventId: '', 82 | time: '' 83 | }, 84 | //系统信息 85 | systemInfo: {}, 86 | deviceUdid: '', 87 | debug: false, 88 | //传入的字符串最大长度限制 89 | maxStringLength: 255, 90 | trackLinksTimeout: 300, 91 | costTime: {}, 92 | appVersion: '', 93 | //重新定义埋点的数据发送函数 94 | //fn :重写发送的数据函数 95 | //start : 设置为true后,fn即启动,默认为false 96 | sendConfig: { 97 | start: false, 98 | //params: url, method, success, fail, data 99 | fn: function(params) {} 100 | }, 101 | // 发送数据异常上报开关,默认为false 102 | sendError: false 103 | }, 104 | //获取系统信息完成标志,默认 false,未完成 105 | getSystemInfoComplete: false, 106 | //发送事件队列集合 107 | queue: [], 108 | disabledEvents: [], 109 | /** 110 | * 信息保存到本地 111 | * 若失败,尝试保存,最多尝试2次 112 | */ 113 | set() { 114 | var self = this; 115 | var count = 0; 116 | var saveLocal = function() { 117 | var saveComplete = _.localStorage.set('config', JSON.stringify(self['config'])); 118 | var errorMsg = saveComplete.errorMsg; 119 | // 当保存数据到本地失败后,重试后还失败上报异常数据 120 | if (!saveComplete.isOk) { 121 | if(2 > count) { 122 | count++; 123 | saveLocal(); 124 | } else { 125 | // 尝试2次还是失败时,上报异常数据 126 | if (typeof errorMsg !== 'object') { 127 | errorMsg = { 128 | errorMsg: errorMsg 129 | }; 130 | } 131 | self.daSendError(errorMsg); 132 | } 133 | } 134 | }; 135 | saveLocal(); 136 | }, 137 | init(appKey, config) { 138 | var localConfig = _.localStorage.get('config'); 139 | if(_.isJSONString(localConfig)) { 140 | localConfig = JSON.parse(localConfig); 141 | _.extend(this['config'], localConfig || {}); 142 | } 143 | _.extend(this['config'], config || {}); 144 | this.getSystem(); 145 | this.setConfig('appKey', appKey); 146 | this.daActivate(); 147 | }, 148 | /** 149 | * 获取配置信息 150 | */ 151 | getConfig(propName) { 152 | return this['config'][propName]; 153 | }, 154 | /** 155 | * 设置配置信息 156 | */ 157 | setConfig(propName, propVal) { 158 | this['config'][propName] = propVal; 159 | }, 160 | /** 161 | * 设置配置信息,有就不设置 162 | */ 163 | setConfigOnce(propName, propVal) { 164 | if(!this['config'][propName]) { 165 | this.setConfig(propName, propVal); 166 | this.set(); 167 | } 168 | }, 169 | /** 170 | * 获取本地标识 171 | */ 172 | getDeviceUdid() { 173 | var localDeviceUdid = this.getConfig('deviceUdid'); 174 | if(!localDeviceUdid) { 175 | localDeviceUdid = _.localStorage.get('deviceUdid'); 176 | this.setConfig('deviceUdid', localDeviceUdid ); 177 | this.set(); 178 | } 179 | return localDeviceUdid; 180 | }, 181 | /** 182 | * 获取用户useId 183 | */ 184 | getUserId() { 185 | return this.getConfig('userId'); 186 | }, 187 | /** 188 | * 获取系统信息 189 | */ 190 | getSystem() { 191 | var self = this; 192 | _.info.callback = function(systemInfo) { 193 | self.getSystemInfoComplete = true; 194 | self.setConfig('systemInfo', systemInfo); 195 | self.set(); 196 | if(self.queue.length > 0) { 197 | _.each(self.queue, function(t) { 198 | self.send.apply(self, Array.prototype.slice.call(t)); 199 | }); 200 | self.queue = []; 201 | } 202 | }; 203 | _.info.getSystem(); 204 | }, 205 | // 设置当前页路径,不带参数 206 | setRoute(route) { 207 | //临时设置 route地址,不保存到本地 208 | this['config']['route'] = route; 209 | }, 210 | getRoute() { 211 | return this['config']['route']; 212 | }, 213 | // 设置当前页url,带参数 214 | setUrl(route) { 215 | // 保存到本地 216 | var pageParameter = this.getPageParameter(); 217 | route = route ? route : this.getRoute(); 218 | if (pageParameter) { 219 | this['config']['url'] = route + pageParameter; 220 | } else { 221 | this['config']['url'] = route; 222 | } 223 | // this.set(); 224 | }, 225 | getUrl(route) { 226 | return this['config']['url']; 227 | }, 228 | setReferrer(referrer) { 229 | referrer = typeof referrer !== 'undefined' ? referrer : this.getUrl(); 230 | this.setOldReferrer(this['config']['referrer']); 231 | this['config']['referrer'] = referrer; 232 | }, 233 | setOldReferrer(referrer) { 234 | if (this['config']['oldReferrer'] !== referrer) { 235 | this['config']['oldReferrer'] = referrer; 236 | } 237 | }, 238 | // 当后台切换到前台时,调用 239 | repeatSetReferrer() { 240 | this['config']['referrer'] = this['config']['oldReferrer']; 241 | }, 242 | getReferrer() { 243 | return this['config']['referrer']; 244 | }, 245 | // 获取当前页面参数 246 | getPageParameter() { 247 | var currentPages = getCurrentPages(); 248 | var route = this.getRoute(); 249 | var obj = {}; 250 | var str = ''; 251 | for (var i = 0; i < currentPages.length; i += 1) { 252 | if (currentPages[i].route === route) { 253 | obj = currentPages[i].options; 254 | break; 255 | } 256 | } 257 | for(var key in obj) { 258 | if (obj.hasOwnProperty(key)) { 259 | if (str === '') { 260 | str = '?' + key + '=' + obj[key]; 261 | } else { 262 | str += '&' + key + '=' + obj[key]; 263 | } 264 | } 265 | } 266 | return str; 267 | }, 268 | /** 269 | * session 开始 270 | */ 271 | sessionStart() { 272 | //如果上次的session close未发送,再次发送 273 | if(this.getConfig('sessionUuid')) { 274 | this.sessionClose(); 275 | } 276 | this.setConfig('sessionUuid', _.UUID()); 277 | this.setConfig('sessionStartTime', new Date().getTime()); 278 | this.track('da_session_start'); 279 | }, 280 | /** 281 | * session 结束 282 | */ 283 | sessionClose() { 284 | var sessionStartTime = this.getConfig('sessionStartTime'); 285 | var lastEvent = this.getConfig('lastEvent') || { 286 | time: new Date().getTime(), 287 | eventId: '' 288 | }; 289 | var sessionCloseTime = lastEvent.time; 290 | var sessionTotalLength = sessionCloseTime - sessionStartTime; 291 | this.track('da_session_close', { 292 | sessionCloseTime: sessionCloseTime, 293 | sessionTotalLength: sessionTotalLength 294 | }); 295 | this.setConfig('sessionUuid', ''); 296 | }, 297 | /** 298 | * da_activate事件 299 | */ 300 | daActivate() { 301 | var localDeviceUdid = this.getConfig('deviceUdid'); 302 | if(!localDeviceUdid) { 303 | localDeviceUdid = _.localStorage.get('deviceUdid'); 304 | this.setConfig('deviceUdid', localDeviceUdid ); 305 | this.track('da_activate'); 306 | this.set(); 307 | } 308 | }, 309 | /** 310 | * 上报异常数据事件 da_send_error 311 | * @param {Object} error 312 | */ 313 | daSendError(error) { 314 | if (!error) { 315 | this.track('da_send_error', error); 316 | } 317 | }, 318 | setEventTimer(eventName, timestamp) { 319 | var timers = this.getConfig('costTime') || {}; 320 | timers[eventName] = timestamp; 321 | this.setConfig('costTime', timers); 322 | }, 323 | removeEventTimer(eventName) { 324 | var timers = this.getConfig('costTime') || {}; 325 | var timestamp = timers[eventName]; 326 | if(!_.isUndefined(timestamp)) { 327 | delete timers[eventName]; 328 | this.setConfig('costTime', timers); 329 | } 330 | return timestamp; 331 | }, 332 | /** 333 | * 统计事件耗时(ms),参数为事件名称。触发一次后移除该事件的耗时监听 334 | */ 335 | time_event(eventName) { 336 | if(_.isUndefined(eventName)) { 337 | _.console('必须传入事件名称'); 338 | return; 339 | } 340 | this.setEventTimer(eventName, new Date().getTime()); 341 | }, 342 | /** 343 | * pv 344 | */ 345 | track_pageview(properties) { 346 | this.track('da_screen', properties || {}); 347 | }, 348 | /** 349 | * 用户注册 350 | */ 351 | signup(userId) { 352 | var oldUserId = this.getConfig('userId'); 353 | oldUserId = oldUserId == undefined ? '' : oldUserId; 354 | if(oldUserId == userId){ 355 | return; 356 | } 357 | this.setConfig('userId', userId); 358 | this.set(); 359 | this.track('da_u_signup',{ 360 | "oldUserId": oldUserId, 361 | "newUserId": userId 362 | }); 363 | }, 364 | /** 365 | * 用户登录记住用户名 366 | * @param {String|Number} 用户唯一标识 367 | */ 368 | login(userId) { 369 | this.signup(userId); 370 | this.track('da_u_login'); 371 | }, 372 | /** 373 | * 用户退出,清除用户id 374 | */ 375 | logout(callback) { 376 | this.setConfig('userId', ''); 377 | this.set(); 378 | var hasCalled = false; 379 | function trackCallback() { 380 | if(!hasCalled) { 381 | hasCalled = true; 382 | if(typeof callback === 'function') { 383 | callback(); 384 | } 385 | } 386 | } 387 | //如果没有回调成功,设置超时回调 388 | setTimeout(trackCallback, this.getConfig('trackLinksTimeout')); 389 | var data = this.track('da_u_logout', {}, trackCallback); 390 | return data; 391 | }, 392 | /** 393 | * 数据发送 394 | */ 395 | send(data, callback) { 396 | if (!this.getSystemInfoComplete) return (this.queue.push(arguments), !1); 397 | var count = 0; 398 | var url = this.getConfig('apiHost') + '/track/w/'; 399 | var systemInfo = this.getConfig('systemInfo'); 400 | var basicInfo = { 401 | 'deviceOs': systemInfo.deviceOs, 402 | 'deviceOsVersion': systemInfo.deviceOsVersion, 403 | 'devicePlatform': systemInfo.devicePlatform, 404 | 'weixinVersion': systemInfo.weixinVersion, 405 | 'screenWidth': systemInfo.screenWidth, 406 | 'screenHeight': systemInfo.screenHeight, 407 | 'deviceModel': systemInfo.deviceModel, 408 | 'networkType': systemInfo.networkType, 409 | 'localeLanguage': systemInfo.localeLanguage, 410 | 'appVersion': this.getConfig('appVersion') 411 | }; 412 | _.extend(data.data, basicInfo); 413 | var truncatedData = _.truncate(data['data'], this.getConfig('maxStringLength')); 414 | var jsonData = JSON.stringify(truncatedData); 415 | var encodedData = _.base64Encode(jsonData); 416 | var appkeyData = _.sha1(this.getConfig('appKey')); 417 | if(this.getConfig('debug')) { 418 | _.console(truncatedData); 419 | } 420 | data['data'] = encodedData; 421 | data['_'] = new Date().getTime().toString(); 422 | data['appKey'] = appkeyData; 423 | url += '?' + _.HTTPBuildQuery(data); 424 | var sendData = function() { 425 | wx.request({ 426 | url: url, 427 | method: "GET", 428 | success: function(res) { 429 | if(typeof callback === 'function') { 430 | callback(res, data); 431 | } 432 | }, 433 | fail: function() { 434 | _.console("发送错误,重新发送"); 435 | if(2 > count) { 436 | count++; 437 | sendData() 438 | } 439 | } 440 | }); 441 | }; 442 | if( this.getConfig('sendConfig').start ) { 443 | if(typeof this.getConfig('sendConfig').fn === 'function') { 444 | var successFn = function(res) { 445 | if(typeof callback === 'function') { 446 | callback(res, truncatedData); 447 | } 448 | }; 449 | var failFn = function(e) { 450 | _.console("发送错误,重新发送"); 451 | }; 452 | this.getConfig('sendConfig').fn({url: url, method: 'GET', success: successFn, fail: failFn, data: _.HTTPBuildQuery(data)}); 453 | } 454 | } else { 455 | sendData(); 456 | } 457 | }, 458 | /** 459 | * 发送事件 460 | */ 461 | track(eventName, properties, callback) { 462 | properties = properties || {}; 463 | var dataType = DATATYPE; 464 | var otherProperties = {}; 465 | var userSetProperties = JSON.parse( JSON.stringify(properties) ); 466 | //事件耗时(ms) 467 | var startTimestamp = this.removeEventTimer(eventName); 468 | if(!_.isUndefined(startTimestamp)) { 469 | otherProperties['costTime'] = new Date().getTime() - startTimestamp; 470 | } 471 | //如果是内置事件,事件类型重新设置 472 | if(DEFAULTEVENTID[eventName]) { 473 | dataType = DEFAULTEVENTID[eventName].dataType; 474 | } 475 | //时间 476 | var time = new Date().getTime(); 477 | //事件为 da_session_close 478 | //自定义属性中删除不需要的属性 479 | if(eventName == 'da_session_close') { 480 | time = properties.sessionCloseTime; 481 | delete userSetProperties['sessionCloseTime']; 482 | delete userSetProperties['sessionTotalLength']; 483 | } 484 | //事件为 da_session_start 485 | if(eventName == 'da_session_start') { 486 | time = this.getConfig('sessionStartTime'); 487 | } 488 | 489 | this.setConfigOnce('persistedTime', time); 490 | var systemInfo = this.getConfig('systemInfo'); 491 | var data = { 492 | 'dataType': dataType, 493 | 'eventId': eventName, 494 | 'appKey': this.getConfig('appKey'), 495 | 'sessionUuid': this.getConfig('sessionUuid'), 496 | 'userId': this.getConfig('userId'), 497 | 'currentUrl': this.getUrl(), 498 | 'sdkVersion': lLIBVERSION, 499 | 'sdkType': SDKTYPE, 500 | 'sessionTotalLength': properties.sessionTotalLength, 501 | 'time': time, 502 | 'persistedTime': this.getConfig('persistedTime'), 503 | 'deviceUdid': this.getDeviceUdid(), 504 | 'urlPath': this.getRoute(), 505 | 'referrer': this.getReferrer(), 506 | 'attributes': userSetProperties 507 | }; 508 | if(!_.isUndefined(otherProperties['costTime'])) { 509 | data['costTime'] = otherProperties['costTime']; 510 | } 511 | this.send({'data': data}, callback); 512 | 513 | //最后一次触发的事件,解决 514 | //session_close 事件的时间计算 515 | if(['da_session_close','da_session_start'].indexOf(eventName) === -1) { 516 | this.setConfig('lastEvent', { 517 | eventId: eventName, 518 | time: time 519 | }); 520 | } 521 | }, 522 | /** 523 | * 发送用户属性 524 | * 525 | * peopleSet.set('gender', '男'); 526 | * or 527 | * peopleSet.set({'gender':'男'}); 528 | */ 529 | peopleSet(properties, to, callback) { 530 | var data = { 531 | 'dataType': 'ie', 532 | 'appKey': this.getConfig('appKey'), 533 | 'deviceUdid': this.getDeviceUdid(), 534 | 'userId': this.getConfig('userId'), 535 | 'time': new Date().getTime(), 536 | 'sdkType': SDKTYPE, 537 | 'eventId': 'da_user_profile', 538 | 'persistedTime': this.getConfig('persistedTime') 539 | }; 540 | var $set = { 541 | '$userProfile': { 542 | '$type': 'profile_set' 543 | } 544 | }; 545 | if(_.isObject(properties)) { 546 | _.each(properties, function(v, k) { 547 | $set['$userProfile'][k] = v; 548 | }, this); 549 | callback = to; 550 | } else { 551 | $set['$userProfile'][prop] = to; 552 | } 553 | data['attributes'] = $set; 554 | this.send({'data': data}, callback); 555 | }, 556 | /** 557 | * 用户属性 558 | */ 559 | people: { 560 | /** 561 | * 设置自定义用户属性 562 | */ 563 | set(properties, to, callback) { 564 | DATracker.peopleSet(properties, to, callback); 565 | }, 566 | /** 567 | * 设置: 姓名 568 | */ 569 | set_realname(realname) { 570 | DATracker.peopleSet({"$realName" : realname}); 571 | }, 572 | /** 573 | * 设置: 国家 574 | */ 575 | set_country(country) { 576 | DATracker.peopleSet({"$country" : country}); 577 | }, 578 | /** 579 | * 设置:省份 580 | */ 581 | set_province(province) { 582 | DATracker.peopleSet({"$region" : province}); 583 | }, 584 | /** 585 | * 设置:城市 586 | */ 587 | set_city(city) { 588 | DATracker.peopleSet({"$city" : city}); 589 | }, 590 | /** 591 | * 设置:性别 0-女,1-男,2-未知 592 | */ 593 | set_gender(gender) { 594 | if ([0,1,2].indexOf(gender) > -1) { 595 | DATracker.peopleSet({"$gender" : gender}); 596 | } 597 | }, 598 | /** 599 | * 设置:生日 600 | */ 601 | set_birthday(birthday) { 602 | if(!_.checkTime(birthday)) return; 603 | DATracker.peopleSet({"$birthday" : birthday}); 604 | }, 605 | /** 606 | * 大集合:账户 + 姓名 + 生日 + 性别 607 | */ 608 | set_populationWithAccount(account, realname, birthday, gender) { 609 | if(!account || !realname || !birthday || [0,1,2].indexOf(gender) === -1) return; 610 | if(!_.checkTime(birthday)) return; 611 | //生日合法检测,yy-MM-dd 612 | DATracker.peopleSet({'$account': account, "$realName" : realname, "$birthday": birthday, "$gender": gender}); 613 | }, 614 | /** 615 | * 国家 + 省份 + 城市 616 | */ 617 | set_location(country, region, city) { 618 | if(!country || !region || !city) return; 619 | DATracker.peopleSet({"$country" : country, "$region": region, "$city": city}); 620 | } 621 | } 622 | }; 623 | 624 | //当应用初始化时触发该方法 625 | function appLaunch() { 626 | this['DATracker'] = DATracker; 627 | DATracker.setReferrer(''); 628 | DATracker.setOldReferrer(''); 629 | } 630 | 631 | function appShow() { 632 | // 后台切换到前台,page隐藏重新设置的referrer是本页 currentUrl,这时候 referrer是不对的,需要判断重新设置 633 | DATracker.repeatSetReferrer(); 634 | DATracker.sessionStart(); 635 | DATracker.set(); 636 | } 637 | 638 | function appHide() { 639 | DATracker.sessionClose(); 640 | DATracker.set(); 641 | } 642 | 643 | //当页面显示时触发该方法 644 | // __route__ 参考: http://www.jb51.net/article/110067.htm 645 | function pageOnshow() { 646 | var self = this; 647 | var route = ("string" == typeof self.__route__) ? self.__route__ : ""; 648 | DATracker.setRoute(route); 649 | DATracker.setUrl(); 650 | var onPageShow = function() { 651 | if(DATracker.config.onPageShow) { 652 | DATracker.config.onPageShow(DATracker, route, self); 653 | } else { 654 | DATracker.track_pageview(); 655 | } 656 | }; 657 | onPageShow(); 658 | } 659 | 660 | // 当页面离开时触发,设置referrer 661 | function onHide() { 662 | DATracker.setReferrer(); 663 | DATracker.set(); 664 | } 665 | 666 | function onUnload() { 667 | DATracker.setReferrer(); 668 | DATracker.set(); 669 | } 670 | 671 | var p = App; 672 | var v = Page; 673 | //重新定义 App 674 | App = function(obj) { 675 | //添加监听,重新定义 onLaunch、onShow、onHide 676 | on(obj, "onLaunch", appLaunch); 677 | on(obj, "onShow", appShow); 678 | on(obj, "onHide", function() {}); 679 | //实例化App 680 | p(obj); 681 | }; 682 | //重新定义 Page 683 | Page = function(obj) { 684 | //添加监听,重新定义 onLoad、onUnload、onShow、onHide 685 | on(obj, "onLoad", function() {}); 686 | on(obj, "onUnload", onUnload); 687 | on(obj, "onShow", pageOnshow); 688 | on(obj, "onHide", onHide); 689 | //实例化Page 690 | v(obj); 691 | }; 692 | 693 | 694 | export default DATracker; -------------------------------------------------------------------------------- /boilerplate/miniprogram/utils/config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | clientVersion: '1.0.0', 3 | protocolVersion: '1.0.4', 4 | host: 'test.du.163.com' 5 | } 6 | export default config -------------------------------------------------------------------------------- /boilerplate/miniprogram/utils/format.js: -------------------------------------------------------------------------------- 1 | export const formatCount = function (value) { 2 | if (value > 99) { 3 | return '99+'; 4 | } 5 | return value; 6 | } 7 | 8 | 9 | export const padding = (value) => { 10 | value = value + ''; 11 | if (value.length === 1) { 12 | return '0' + value; 13 | } 14 | 15 | return value; 16 | } 17 | 18 | export const formatDateFuture = (timestamp) => { 19 | const nowDate = new Date(); 20 | const now = nowDate.getTime(); 21 | 22 | timestamp = /\d+/.test(timestamp) ? parseInt(timestamp, 10) : timestamp; 23 | 24 | let diff = Math.floor((timestamp - now) / 1000 / 60 ); 25 | 26 | if(diff < 60){ 27 | return `${diff}分钟后` 28 | } 29 | 30 | diff /= 60 31 | 32 | if(diff < 24){ 33 | diff = Math.floor(diff) 34 | return `${diff}小时后` 35 | } 36 | 37 | diff /= 24 38 | 39 | diff = Math.floor(diff) 40 | 41 | if(diff <= 7 ){ 42 | return `${diff}天后` 43 | } 44 | 45 | const targetDate = new Date(timestamp); 46 | return `${targetDate.getMonth() + 1}月${targetDate.getDate()}日${targetDate.getHours()}点` 47 | 48 | } 49 | 50 | export const formatDate = (timestamp) => { 51 | const nowDate = new Date(); 52 | const now = nowDate.getTime(); 53 | 54 | timestamp = /\d+/.test(timestamp) ? parseInt(timestamp, 10) : timestamp; 55 | 56 | const targetDate = new Date(timestamp); 57 | let diff = (now - timestamp) / 1000; //秒 58 | 59 | if (diff < 60) { 60 | return '刚刚'; 61 | } 62 | 63 | diff /= 60; //分 64 | 65 | if(diff < 60){ 66 | return parseInt(diff) + '分钟前' 67 | } 68 | 69 | diff /= 60; //时 70 | 71 | const hours = padding(targetDate.getHours()) + ':' + padding(targetDate.getMinutes()); 72 | 73 | if (diff < nowDate.getHours()) { 74 | return '今天' + hours; 75 | } else if (diff < nowDate.getHours() + 24) { 76 | return '昨天' + hours; 77 | } else if (diff < nowDate.getHours() + 48) { 78 | return '前天' + hours; 79 | } 80 | 81 | const days = (targetDate.getMonth() + 1) + '月' + targetDate.getDate() + '日'; 82 | 83 | if (targetDate.getUTCFullYear() === nowDate.getUTCFullYear()) { 84 | return days + ' ' + hours; 85 | } 86 | 87 | return targetDate.getUTCFullYear() + '年' + ' ' + days; 88 | } 89 | -------------------------------------------------------------------------------- /boilerplate/miniprogram/utils/utils.js: -------------------------------------------------------------------------------- 1 | import wxAPI from './wxAPI' 2 | import { 3 | reqwest 4 | } from '../model/fetchAPI' 5 | 6 | 7 | // 蜗牛用于上报formId,其他产品问问后端能否跨域 8 | export const sendFormId = function (formId) { 9 | let openId = wx.getStorageSync('openId') 10 | if (!openId || !formId) return 11 | 12 | console.log('formId', formId) 13 | if (formId === 'the formId is a mock one') { 14 | console.log('formId 测试提交成功') 15 | return 16 | } 17 | reqwest({ 18 | url: '/minicommon/uploadFormId.json', 19 | method: 'GET', 20 | data: { 21 | formId, 22 | openId, 23 | } 24 | }).then(resp => { 25 | if (resp.code === 0) { 26 | console.log('formId上报成功') 27 | } else { 28 | wx.showToast({ 29 | title: resp.msg, 30 | icon: 'none', 31 | duration: 3000 32 | }) 33 | } 34 | }) 35 | } 36 | 37 | 38 | // 蜗牛小程序登录获取token 39 | export const weixinLogin = function (callBack) { 40 | wxAPI.wxLogin().then(resp => { 41 | let { 42 | code 43 | } = resp 44 | 45 | wxAPI.wxGetSetting().then(resp => { 46 | if (resp.authSetting['scope.userInfo']) { 47 | wxAPI.wxGetUserInfo({ 48 | withCredentials: true 49 | }).then(resp => { 50 | console.log('成功获取用户信息:', resp) 51 | let { 52 | encryptedData, 53 | iv, 54 | userInfo: { 55 | nickName, 56 | avatarUrl, 57 | gender, 58 | } 59 | } = resp 60 | 61 | reqwest({ 62 | url: '/login/miniprogram', 63 | header: { 64 | "content-type": "application/x-www-form-urlencoded" 65 | }, 66 | data: { 67 | code, 68 | encryptedData, 69 | iv, 70 | nickName, 71 | avatarUrl, 72 | gender 73 | }, 74 | method: 'POST' 75 | }).then(resp => { 76 | if (resp.code === 0) { 77 | wx.setStorageSync('authToken', resp.authToken) 78 | // 用于获取模板消息 79 | fetchOpenId() 80 | // sendLoginRecord(1) 81 | if (needUserInfo) { 82 | return fetchUserInfo() 83 | } else { 84 | fetchUserInfo() 85 | callBack && callBack() 86 | } 87 | } else { 88 | wx.showToast({ 89 | title: `登录失败`, 90 | icon: 'none', 91 | duration: 3000 92 | }) 93 | } 94 | }) 95 | }) 96 | } 97 | }) 98 | }) 99 | } 100 | 101 | // 发送模板消息需要openId 102 | export const fetchOpenId = () => { 103 | wxAPI.wxLogin().then(resp => { 104 | let { 105 | code 106 | } = resp 107 | 108 | return code 109 | }).then(code => { 110 | return reqwest({ 111 | url: '/minicommon/openId', 112 | method: 'GET', 113 | data: { 114 | code, 115 | } 116 | }) 117 | }).then(({ 118 | openId 119 | }) => { 120 | wx.setStorageSync('openId', openId) 121 | }) 122 | } 123 | 124 | export const sendLoginRecord = type => { 125 | if(getApp()){ 126 | console.log('sendLoginRecord', type); 127 | reqwest({ 128 | url: '/couple/login/record.json', 129 | method: 'POST', 130 | data: { 131 | type 132 | }, 133 | header: { 134 | 'Content-Type': 'application/x-www-form-urlencoded' 135 | } 136 | }) 137 | } 138 | } 139 | 140 | export const fetchUserInfo = () => { 141 | reqwest({ 142 | url: '/user/info.json', 143 | method: 'GET' 144 | }).then(resp => { 145 | if (resp.code === 0) { 146 | const {user} = resp; 147 | 148 | wx.setStorageSync('user', user); 149 | if (getApp()) { 150 | getApp().DATracker.login(user.userId) 151 | } 152 | return Promise.resolve(user); 153 | } else { 154 | wx.showToast({ 155 | title: resp.msg, 156 | icon: 'none', 157 | duration: 3000 158 | }) 159 | return Promise.reject(); 160 | } 161 | }) 162 | } 163 | 164 | export const getUserInfo = () => { 165 | return new Promise(resolve => { 166 | const userInfo = wx.getStorageSync('user'); 167 | if(userInfo){ 168 | resolve(userInfo) 169 | }else{ 170 | return weixinLogin(null, null, true) 171 | } 172 | }) 173 | } -------------------------------------------------------------------------------- /boilerplate/miniprogram/utils/wxAPI.js: -------------------------------------------------------------------------------- 1 | var appInstance = getApp() 2 | 3 | function wxPromisify(fn) { 4 | return (obj = {}) => { 5 | return new Promise((resolve, reject) => { 6 | obj.success = (resp) => { 7 | if (resp.statusCode !== undefined && resp.statusCode !== 200) { 8 | console.log("fail", resp) 9 | reject(resp) 10 | } else { 11 | resolve(resp) 12 | } 13 | } 14 | obj.fail = (resp) => { 15 | reject(resp) 16 | } 17 | fn(obj) 18 | }) 19 | } 20 | } 21 | 22 | Promise.prototype.finally = function (callback) { 23 | let P = this.constructor; 24 | return this.then( 25 | value => P.resolve(callback()).then(() => value), 26 | reason => P.resolve(callback()).then(() => { 27 | throw reason 28 | }) 29 | ); 30 | } 31 | 32 | /** 33 | * 微信用户登录,获取code 34 | */ 35 | function wxRequest() { 36 | return wxPromisify(wx.request) 37 | } 38 | 39 | function wxCheckSession(obj) { 40 | return wxPromisify(wx.checkSession)(obj) 41 | } 42 | 43 | function wxLogin(obj) { 44 | return wxPromisify(wx.login)(obj).then((res) => { 45 | appInstance.globalData.code = res.code 46 | return Promise.resolve(res) 47 | }) 48 | } 49 | 50 | function wxGetUserInfo(obj) { 51 | return wxPromisify(wx.getUserInfo)(obj).then((res) => { 52 | appInstance.globalData.userInfo = res.userInfo 53 | return Promise.resolve(res) 54 | }); 55 | } 56 | 57 | function wxShowModal(obj) { 58 | return wxPromisify(wx.showModal)(obj) 59 | } 60 | 61 | function wxUploadFile(obj) { 62 | return wxPromisify(wx.uploadFile)(obj) 63 | } 64 | 65 | function wxAuthorize(obj) { 66 | return wxPromisify(wx.authorize)(obj) 67 | } 68 | 69 | function wxGetSetting(obj) { 70 | return wxPromisify(wx.getSetting)(obj) 71 | } 72 | 73 | module.exports = { 74 | wxRequest: wxRequest, 75 | wxCheckSession: wxCheckSession, 76 | wxLogin: wxLogin, 77 | wxGetUserInfo: wxGetUserInfo, 78 | wxUploadFile: wxUploadFile, 79 | wxShowModal: wxShowModal, 80 | wxAuthorize: wxAuthorize, 81 | wxGetSetting: wxGetSetting 82 | } -------------------------------------------------------------------------------- /boilerplate/node/.gitignore.keep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .cache/ 3 | .vscode/ 4 | node_modules/ 5 | /lib 6 | *.log* 7 | -------------------------------------------------------------------------------- /boilerplate/node/.npmignore.keep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .cache/ 3 | .vscode/ 4 | node_modules/ 5 | /src 6 | *.log* 7 | -------------------------------------------------------------------------------- /boilerplate/node/README.md: -------------------------------------------------------------------------------- 1 | # 项目名称 2 | 3 | **【】中的内容需要自己填写,并删除本行** 4 | 5 | 【项目简介】 6 | 7 | ## 开始安装 8 | 9 | 【安装说明】 10 | 11 | ## 如何使用 12 | 13 | 【使用说明】 14 | 15 | ## API 16 | 17 | 【API说明】 18 | 19 | ## 环境配置 20 | 21 | 构建工具 22 | 23 | ``` bash 24 | $ npm install -g fle-cli 25 | 26 | # yarn 27 | $ yarn global add fle-cli 28 | ``` 29 | 30 | 命令说明 31 | 32 | ```bash 33 | # 本地开发 34 | fle dev 35 | 36 | # 代码构建 37 | fle build 38 | ``` 39 | 40 | 查看更多说明: [构建文档](https://www.npmjs.com/package/fle-cli) 41 | 42 | ## 补充说明 43 | 44 | 【备注】 45 | -------------------------------------------------------------------------------- /boilerplate/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fle-boilerplate-node", 3 | "version": "0.0.0", 4 | "description": "A node project created by fle-cli.", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "dev": "NODE_ENV=development nodemon lib/index.js", 8 | "prod": "NODE_ENV=production node lib/index.js" 9 | }, 10 | "keywords": [], 11 | "author": "huangancheng", 12 | "license": "MIT", 13 | "dependencies": {}, 14 | "engines": { 15 | "node": ">=6.11.5" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /boilerplate/node/src/index.js: -------------------------------------------------------------------------------- 1 | function formatDate (date = new Date(), fmt = 'yyyy-MM-dd hh:mm:ss') { 2 | let o = { 3 | MM: date.getMonth() + 1, 4 | dd: date.getDate(), 5 | hh: date.getHours(), 6 | mm: date.getMinutes(), 7 | ss: date.getSeconds() 8 | } 9 | 10 | fmt = fmt.replace('yyyy', date.getFullYear()) 11 | 12 | Object.keys(o).forEach(k => { 13 | fmt = fmt.replace(k, o[k] > 9 ? o[k] : '0' + o[k]) 14 | }) 15 | 16 | return fmt 17 | } 18 | 19 | console.log(formatDate()) 20 | -------------------------------------------------------------------------------- /boilerplate/react/.gitignore.keep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .cache/ 3 | .vscode/ 4 | node_modules/ 5 | /lib 6 | /dist 7 | /public 8 | *.log* 9 | -------------------------------------------------------------------------------- /boilerplate/react/README.md: -------------------------------------------------------------------------------- 1 | # 项目名称 2 | 3 | **【】中的内容需要自己填写,并删除本行** 4 | 5 | 【项目简介】 6 | 7 | ## 如何运行 8 | 9 | > node版本 `>=6.11.5` 10 | 11 | ### 环境配置 12 | 13 | #### 安装全局编译工具 14 | 15 | ``` bash 16 | $ npm install -g fle-cli 17 | 18 | # yarn 19 | $ yarn global add fle-cli 20 | ``` 21 | 22 | 【其他说明】 23 | 24 | ### 开发过程 25 | 26 | #### 命令 27 | 28 | ```bash 29 | # 本地开发 30 | fle dev 31 | 32 | # 代码构建 33 | fle build 34 | ``` 35 | 36 | 查看更多说明: [构建文档](https://www.npmjs.com/package/fle-cli) 37 | 38 | #### 代理配置 39 | 40 | | 本地地址 | 代理地址 | 41 | |---------|--------| 42 | | 【`/api/*`】 | 【`http://xxx`】 | 43 | 44 | ### 线上发布 45 | 46 | 【发布说明】 47 | 48 | ### 项目维护 49 | 50 | | 角色 | 人员 | 51 | |---------|----------| 52 | | 前端开发 | 【xxx】、【yyy】 | 53 | | 后端开发 | 【xxx】 | 54 | | 产品经理 | 【xxx】 | 55 | | 交互设计 | 【xxx】 | 56 | 57 | ### 其他说明 58 | 59 | * 【[数据上报](http://xxx)】 60 | * 【[需求文档](http://xxx)】 61 | * 【[设计稿](http://xxx)】 62 | 63 | ## 业务介绍 64 | 65 | 【业务描述】 66 | 67 | ### 业务入口 68 | 69 | * 【AAA】 70 | * 【BBB】 71 | * 【CCC】 72 | 73 | 【补充说明】 74 | 75 | ### 页面信息 76 | 77 | |页面目录|页面描述|页面链接|参数描述| 78 | |-------|------|-------|-------| 79 | |【index】 | 【首页】 | 【[https://xxx.com](https://xxx.com/)】 | 无 | 80 | 81 | ## 其他事项 82 | 83 | 补充说明 84 | 85 | > 【项目备注】 86 | -------------------------------------------------------------------------------- /boilerplate/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fle-boilerplate-react", 3 | "version": "0.0.0", 4 | "description": "A React project created by fle-cli.", 5 | "keywords": ["fle", "webpack", "react"], 6 | "author": "huangancheng", 7 | "license": "MIT", 8 | "dependencies": { 9 | "react": "*", 10 | "react-dom": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /boilerplate/react/src/example/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Hello from './components/Hello' 3 | import './global.css' 4 | 5 | export default class App extends Component { 6 | render () { 7 | return ( 8 |
9 | 10 |
11 | ) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /boilerplate/react/src/example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "示例", 3 | "keyswords": "", 4 | "description": "", 5 | "icon": "", 6 | "template": "/default.html", 7 | "compiled": true 8 | } 9 | -------------------------------------------------------------------------------- /boilerplate/react/src/example/components/Hello/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /boilerplate/react/src/example/components/Hello/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import $style from './style.module.css' 3 | 4 | export default class Hello extends Component { 5 | render () { 6 | return ( 7 |
8 |
9 | logo 10 |

Welcome to React

11 |
12 |

13 | To get started, edit App.js and save to reload. 14 |

15 |
16 | ) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /boilerplate/react/src/example/components/Hello/style.module.css: -------------------------------------------------------------------------------- 1 | .app { 2 | text-align: center; 3 | } 4 | 5 | .logo { 6 | animation: logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .title { 18 | font-size: 1.5em; 19 | } 20 | 21 | .intro { 22 | font-size: large; 23 | } 24 | 25 | @keyframes logo-spin { 26 | from { transform: rotate(0deg); } 27 | to { transform: rotate(360deg); } 28 | } 29 | -------------------------------------------------------------------------------- /boilerplate/react/src/example/global.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /boilerplate/react/src/example/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import App from './App' 4 | 5 | render(, document.getElementById('root')) 6 | -------------------------------------------------------------------------------- /boilerplate/vue/.gitignore.keep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .cache/ 3 | .vscode/ 4 | node_modules/ 5 | /lib 6 | /dist 7 | /public 8 | *.log* 9 | -------------------------------------------------------------------------------- /boilerplate/vue/README.md: -------------------------------------------------------------------------------- 1 | # 项目名称 2 | 3 | **【】中的内容需要自己填写,并删除本行** 4 | 5 | 【项目简介】 6 | 7 | ## 如何运行 8 | 9 | > node版本 `>=6.11.5` 10 | 11 | ### 环境配置 12 | 13 | #### 安装全局编译工具 14 | 15 | ``` bash 16 | $ npm install -g fle-cli 17 | 18 | # yarn 19 | $ yarn global add fle-cli 20 | ``` 21 | 22 | 【其他说明】 23 | 24 | ### 开发过程 25 | 26 | #### 命令 27 | 28 | ```bash 29 | # 本地开发 30 | fle dev 31 | 32 | # 代码构建 33 | fle build 34 | ``` 35 | 36 | 查看更多说明: [构建文档](https://www.npmjs.com/package/fle-cli) 37 | 38 | #### 代理配置 39 | 40 | | 本地地址 | 代理地址 | 41 | |---------|--------| 42 | | 【`/api/*`】 | 【`http://xxx`】 | 43 | 44 | ### 线上发布 45 | 46 | 【发布说明】 47 | 48 | ### 项目维护 49 | 50 | | 角色 | 人员 | 51 | |---------|----------| 52 | | 前端开发 | 【xxx】、【yyy】 | 53 | | 后端开发 | 【xxx】 | 54 | | 产品经理 | 【xxx】 | 55 | | 交互设计 | 【xxx】 | 56 | 57 | ### 其他说明 58 | 59 | * 【[数据上报](http://xxx)】 60 | * 【[需求文档](http://xxx)】 61 | * 【[设计稿](http://xxx)】 62 | 63 | ## 业务介绍 64 | 65 | 【业务描述】 66 | 67 | ### 业务入口 68 | 69 | * 【AAA】 70 | * 【BBB】 71 | * 【CCC】 72 | 73 | 【补充说明】 74 | 75 | ### 页面信息 76 | 77 | |页面目录|页面描述|页面链接|参数描述| 78 | |-------|------|-------|-------| 79 | |【index】 | 【首页】 | 【[https://xxx.com](https://xxx.com/)】 | 无 | 80 | 81 | ## 其他事项 82 | 83 | 补充说明 84 | 85 | > 【项目备注】 86 | -------------------------------------------------------------------------------- /boilerplate/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fle-boilerplate-vue", 3 | "version": "0.0.0", 4 | "description": "A Vue project created by fle-cli.", 5 | "keywords": ["fle", "webpack", "vue"], 6 | "author": "huangancheng", 7 | "license": "MIT", 8 | "dependencies": { 9 | "vue": "^2.5.16" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /boilerplate/vue/src/example/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 21 | 22 | 32 | -------------------------------------------------------------------------------- /boilerplate/vue/src/example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "示例", 3 | "keyswords": "", 4 | "description": "", 5 | "icon": "", 6 | "template": "/default.html", 7 | "compiled": true 8 | } 9 | -------------------------------------------------------------------------------- /boilerplate/vue/src/example/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 94 | 95 | 105 | 106 | 129 | -------------------------------------------------------------------------------- /boilerplate/vue/src/example/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansenhuang/fle-cli/96ede8e95c5b4f582946f44de9e667aeea1598cb/boilerplate/vue/src/example/images/logo.png -------------------------------------------------------------------------------- /boilerplate/vue/src/example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | /* eslint-disable no-new */ 5 | new Vue({ 6 | el: '#root', 7 | render: h => h(App) 8 | }) 9 | -------------------------------------------------------------------------------- /build/.share/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansenhuang/fle-cli/96ede8e95c5b4f582946f44de9e667aeea1598cb/build/.share/images/favicon.ico -------------------------------------------------------------------------------- /build/.share/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansenhuang/fle-cli/96ede8e95c5b4f582946f44de9e667aeea1598cb/build/.share/images/logo.png -------------------------------------------------------------------------------- /build/.share/template/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 | 9 | <% if (htmlWebpackPlugin.options.icon) { %> 10 | 11 | <% } %> 12 | <% for (var i = 0; i < htmlWebpackPlugin.options.css.length; i++) { %> 13 | 14 | <% } %> 15 | <% for (var j = 0; j < htmlWebpackPlugin.options.prejs.length; j++) { %> 16 | 17 | <% } %> 18 | 19 | 20 |
21 | <% for (var k = 0; k < htmlWebpackPlugin.options.js.length; k++) { %> 22 | 23 | <% } %> 24 | 25 | 26 | -------------------------------------------------------------------------------- /build/.share/template/dev.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 | 9 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /build/.share/template/h5/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 | <% if (htmlWebpackPlugin.options.icon) { %> 9 | 10 | <% } %> 11 | <% for (var i = 0; i < htmlWebpackPlugin.options.css.length; i++) { %> 12 | 13 | <% } %> 14 | <% if (htmlWebpackPlugin.options.remUnit != 50) { %> 15 | 18 | <% } %> 19 | <% for (var j = 0; j < htmlWebpackPlugin.options.prejs.length; j++) { %> 20 | 21 | <% } %> 22 | 23 | 24 |
25 | <% for (var k = 0; k < htmlWebpackPlugin.options.js.length; k++) { %> 26 | 27 | <% } %> 28 | 29 | 30 | -------------------------------------------------------------------------------- /build/.share/template/h5/wenman.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 | <% if (htmlWebpackPlugin.options.icon) { %> 9 | 10 | <% } %> 11 | <% for (var i = 0; i < htmlWebpackPlugin.options.css.length; i++) { %> 12 | 13 | <% } %> 14 | 48 | <% for (var j = 0; j < htmlWebpackPlugin.options.prejs.length; j++) { %> 49 | 50 | <% } %> 51 | 52 | 53 |
54 | <% for (var k = 0; k < htmlWebpackPlugin.options.js.length; k++) { %> 55 | 56 | <% } %> 57 | 58 | 59 | -------------------------------------------------------------------------------- /build/.share/template/h5/wenman.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 | <% if (htmlWebpackPlugin.options.icon) { %> 9 | 10 | <% } %> 11 | <% for (var i = 0; i < htmlWebpackPlugin.options.css.length; i++) { %> 12 | 13 | <% } %> 14 | 36 | <% for (var j = 0; j < htmlWebpackPlugin.options.prejs.length; j++) { %> 37 | 38 | <% } %> 39 | 40 | 41 |
42 | <% for (var k = 0; k < htmlWebpackPlugin.options.js.length; k++) { %> 43 | 44 | <% } %> 45 | 46 | 47 | -------------------------------------------------------------------------------- /build/.share/template/pc/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 | 9 | <% if (htmlWebpackPlugin.options.icon) { %> 10 | 11 | <% } %> 12 | <% for (var i = 0; i < htmlWebpackPlugin.options.css.length; i++) { %> 13 | 14 | <% } %> 15 | <% for (var j = 0; j < htmlWebpackPlugin.options.prejs.length; j++) { %> 16 | 17 | <% } %> 18 | 19 | 20 |
21 | <% for (var k = 0; k < htmlWebpackPlugin.options.js.length; k++) { %> 22 | 23 | <% } %> 24 | 25 | 26 | -------------------------------------------------------------------------------- /build/.share/template/pc/wenman.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 | 9 | <% if (htmlWebpackPlugin.options.icon) { %> 10 | 11 | <% } %> 12 | <% for (var i = 0; i < htmlWebpackPlugin.options.css.length; i++) { %> 13 | 14 | <% } %> 15 | <% if (htmlWebpackPlugin.options.uaId) { %> 16 | 32 | <% } %> 33 | <% for (var j = 0; j < htmlWebpackPlugin.options.prejs.length; j++) { %> 34 | 35 | <% } %> 36 | 37 | 38 |
39 | <% for (var k = 0; k < htmlWebpackPlugin.options.js.length; k++) { %> 40 | 41 | <% } %> 42 | 43 | 44 | -------------------------------------------------------------------------------- /build/webpack/babel.js: -------------------------------------------------------------------------------- 1 | var config = require('./config'); 2 | 3 | var babelConfig = { 4 | "ignore": [ 5 | "**/*.min.js" 6 | ], 7 | "presets": [ 8 | [ 9 | require.resolve("@babel/preset-env"), 10 | { 11 | "modules": false, 12 | "loose": true, 13 | "useBuiltIns": 'usage', 14 | "targets": { 15 | "browsers": config.fle.browsers 16 | } 17 | } 18 | ], 19 | config.react && require.resolve("@babel/preset-react") 20 | ].filter(p => p), 21 | "plugins": [ 22 | [require.resolve("@babel/plugin-proposal-decorators"), { "legacy": true }], 23 | require.resolve("@babel/plugin-proposal-export-namespace-from"), 24 | require.resolve("@babel/plugin-syntax-dynamic-import"), 25 | [require.resolve("@babel/plugin-proposal-class-properties"), { "loose": true }], 26 | require.resolve("@babel/plugin-proposal-json-strings"), 27 | require.resolve("@babel/plugin-transform-runtime"), 28 | 29 | config.vue && require.resolve("babel-plugin-transform-vue-jsx") 30 | ].filter(p => p) 31 | }; 32 | 33 | module.exports = babelConfig; 34 | -------------------------------------------------------------------------------- /build/webpack/config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | var __DEV__ = (process.env.NODE_ENV || 'development') === 'development'; 4 | var __LOG__ = process.env.FLE_VCONSOLE === 'true'; 5 | var __UPLOAD__ = process.env.FLE_UPLOAD === 'true'; 6 | var __REPORT__ = process.env.FLE_REPORT === 'true'; 7 | var __COMPILE_PAGES__ = process.env.FLE_COMPILE_PAGES; 8 | var __PORT__ = process.env.FLE_PORT; 9 | 10 | var { resolve } = require('./utils'); 11 | var fle = require(resolve('fle.json')); 12 | var __REACT__ = fle.boilerplate.indexOf('react') !== -1 || (fle.boilerplate === 'lib' && fle.react); 13 | var __VUE__ = fle.boilerplate.indexOf('vue') !== -1 || (fle.boilerplate === 'lib' && fle.vue); 14 | var uploadConfig = __UPLOAD__ ? require(path.join(__dirname, '../../.cdn.json')) : null; 15 | 16 | if (__PORT__) { 17 | fle.port = __PORT__; 18 | } 19 | 20 | if (!fle.externals) { 21 | fle.externals = {}; 22 | } 23 | 24 | if (Array.isArray(fle.prejs)) { 25 | fle.prejs.forEach((item, i) => { 26 | if (typeof item !== 'string') { 27 | fle.externals[item.name] = item.value; 28 | fle.prejs[i] = item.src; 29 | } 30 | }); 31 | } 32 | 33 | if (Array.isArray(fle.js)) { 34 | fle.js.forEach((item, i) => { 35 | if (typeof item !== 'string') { 36 | fle.externals[item.name] = item.value; 37 | fle.js[i] = item.src; 38 | } 39 | }); 40 | } 41 | 42 | module.exports = { 43 | dev: __DEV__, 44 | vconsole: __LOG__, 45 | upload: __UPLOAD__, 46 | report: __REPORT__, 47 | react: __REACT__, 48 | vue: __VUE__, 49 | uploadConfig: uploadConfig, 50 | compilePages: __COMPILE_PAGES__ ? __COMPILE_PAGES__.split(',') : [], 51 | fle: Object.assign({ 52 | // global 53 | eslint: true, 54 | notify: true, 55 | inlineManifest: true, 56 | // vendors: {}, 57 | // business: '', 58 | publicPath: '/', 59 | 60 | // css 61 | remUnit: 50, 62 | 63 | // dev 64 | host: '0.0.0.0', 65 | port: 5000, 66 | proxy: {}, 67 | historyApiFallback: true, 68 | hot: true, 69 | open: false, 70 | https: false, 71 | 72 | // cdn 73 | css: [], 74 | prejs: [], 75 | js: [], 76 | 77 | // others 78 | browsers: [ 79 | 'last 4 versions', 80 | 'ie >= 9', 81 | 'iOS >= 7', 82 | 'Android >= 4' 83 | ], 84 | externals: {}, 85 | libExternals: {} 86 | }, fle) 87 | }; 88 | -------------------------------------------------------------------------------- /build/webpack/eslint.js: -------------------------------------------------------------------------------- 1 | var config = require('./config'); 2 | 3 | var eslintConfig = { 4 | "root": true, 5 | "parserOptions": { 6 | "sourceType": "module" 7 | }, 8 | "env": { 9 | "browser": true, 10 | "es6": true 11 | }, 12 | "globals":{ 13 | "console": true 14 | }, 15 | "settings": { 16 | "react": { 17 | "version": "15.6" 18 | } 19 | }, 20 | "extends": [ 21 | "standard", 22 | config.react && "plugin:react/recommended", 23 | config.vue && "plugin:vue/essential" 24 | ].filter(p => p), 25 | "plugins": [], 26 | "rules": { 27 | "no-var": 1, 28 | "no-alert": 1, 29 | "standard/no-callback-literal": 0, 30 | "prefer-promise-reject-errors": 0, 31 | "no-unused-vars": config.dev ? 1 : 2, 32 | "no-debugger": config.dev ? 1 : 2, 33 | "no-console": [config.dev ? 1 : 2, { 34 | "allow": ["info", "warn", "error"] 35 | }] 36 | } 37 | }; 38 | 39 | if (!config.vue) { 40 | eslintConfig.parser = "babel-eslint"; 41 | } else { 42 | eslintConfig.parserOptions.parser = "babel-eslint"; 43 | } 44 | 45 | module.exports = eslintConfig; 46 | -------------------------------------------------------------------------------- /build/webpack/loader.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | 5 | var config = require('./config'); 6 | var { resolve } = require('./utils'); 7 | var sourceMap = config.dev ? true : (!!config.fle.sourceMap); 8 | 9 | var styleLoader = { 10 | loader: 'style-loader', 11 | options: { 12 | sourceMap: sourceMap 13 | } 14 | }; 15 | 16 | // vue-style 17 | var vueStyleLoader = { 18 | loader: 'vue-style-loader', 19 | options: { 20 | sourceMap: sourceMap 21 | } 22 | }; 23 | 24 | // css 25 | // 支持通过import导入样式变量 26 | var cssLoader = { 27 | loader: 'css-loader', 28 | options: { 29 | sourceMap: sourceMap, 30 | modules: true, 31 | camelCase: true, 32 | importLoaders: 1, 33 | localIdentName: '[local]' 34 | } 35 | }; 36 | 37 | var moduleCSSLoader = { 38 | loader: 'css-loader', 39 | options: { 40 | sourceMap: sourceMap, 41 | modules: true, 42 | camelCase: true, 43 | importLoaders: 1, 44 | localIdentName: '[local]___[hash:base64:8]' 45 | } 46 | }; 47 | 48 | // postcss 49 | var postCSSLoader = { 50 | loader: 'postcss-loader', 51 | options: { 52 | sourceMap: sourceMap, 53 | config: { 54 | path: path.join(__dirname, './postcss.config.js') 55 | } 56 | } 57 | }; 58 | 59 | function getCSSLoaders (modules) { 60 | return config.dev ? 61 | [config.vue ? vueStyleLoader : styleLoader, modules ? moduleCSSLoader : cssLoader, postCSSLoader] 62 | : 63 | [MiniCssExtractPlugin.loader, modules ? moduleCSSLoader : cssLoader, postCSSLoader] 64 | } 65 | 66 | exports.css = () => { 67 | return { 68 | test: /\.css$/, 69 | exclude: /\.module\.css$/, 70 | oneOf: [ 71 | // this matches `