commit 88921a9ac045c212393cb1fb8fd9d5b72e07019e Author: qimengjie Date: Wed Dec 12 14:52:37 2018 +0800 init commit diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..0b40319 --- /dev/null +++ b/.babelrc @@ -0,0 +1,11 @@ +{ + "plugins": [ + ["module-resolver", { + "root": ["./src"], + "alias": {} + }] + ], + "presets": [ + ["env", {"loose": true, "modules": "commonjs"}] + ] +} \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..1f42ef5 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,96 @@ +module.exports = { + 'extends': [ + 'airbnb-base', + 'plugin:promise/recommended' + ], + 'parserOptions': { + 'ecmaVersion': 9, + 'ecmaFeatures': { + 'jsx': false + }, + 'sourceType': 'module' + }, + 'env': { + 'es6': true, + 'node': true, + 'jest': true + }, + 'plugins': [ + 'import', + 'node', + 'promise' + ], + 'rules': { + 'arrow-parens': 'off', + 'comma-dangle': [ + 'error', + 'only-multiline' + ], + 'complexity': ['error', 10], + 'func-names': 'off', + 'global-require': 'off', + 'handle-callback-err': [ + 'error', + '^(err|error)$' + ], + 'import/no-unresolved': [ + 'error', + { + 'caseSensitive': true, + 'commonjs': true, + 'ignore': ['^[^.]'] + } + ], + 'import/prefer-default-export': 'off', + 'linebreak-style': 'off', + 'no-catch-shadow': 'error', + 'no-continue': 'off', + 'no-div-regex': 'warn', + 'no-else-return': 'off', + 'no-param-reassign': 'off', + 'no-plusplus': 'off', + 'no-shadow': 'off', + 'no-multi-assign': 'off', + 'no-underscore-dangle': 'off', + 'node/no-deprecated-api': 'error', + 'node/process-exit-as-throw': 'error', + 'object-curly-spacing': [ + 'error', + 'never' + ], + 'operator-linebreak': [ + 'error', + 'after', + { + 'overrides': { + ':': 'before', + '?': 'before' + } + } + ], + 'prefer-arrow-callback': 'off', + 'prefer-destructuring': 'off', + 'prefer-template': 'off', + 'quote-props': [ + 1, + 'as-needed', + { + 'unnecessary': true + } + ], + 'semi': [ + 'error', + 'never' + ] + }, + 'globals': { + 'window': true, + 'document': true, + 'App': true, + 'Page': true, + 'Component': true, + 'Behavior': true, + 'wx': true, + 'getCurrentPages': true, + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..abb2112 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.idea +.DS_Store +package-lock.json + +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +miniprogram_dist +miniprogram_dev +node_modules +coverage \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..650e4a7 --- /dev/null +++ b/.npmignore @@ -0,0 +1,16 @@ +.idea +.DS_Store +package-lock.json + +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +test +tools +docs +miniprogram_dev +node_modules +coverage \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e78bcd8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 wechat-miniprogram + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..bdf4201 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# miniprogram-picker diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..3ecaab5 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,26 @@ +const gulp = require('gulp') +const clean = require('gulp-clean') + +const config = require('./tools/config') +const BuildTask = require('./tools/build') +const id = require('./package.json').name || 'miniprogram-custom-component' + +// build task instance +// eslint-disable-next-line no-new +new BuildTask(id, config.entry) + +// clean the generated folders and files +gulp.task('clean', gulp.series(() => gulp.src(config.distPath, {read: false, allowEmpty: true}).pipe(clean()), done => { + if (config.isDev) { + return gulp.src(config.demoDist, {read: false, allowEmpty: true}) + .pipe(clean()) + } + + return done() +})) +// watch files and build +gulp.task('watch', gulp.series(`${id}-watch`)) +// build for develop +gulp.task('dev', gulp.series(`${id}-dev`)) +// build for publish +gulp.task('default', gulp.series(`${id}-default`)) diff --git a/package.json b/package.json new file mode 100644 index 0000000..440f004 --- /dev/null +++ b/package.json @@ -0,0 +1,62 @@ +{ + "name": "miniprogram-picker", + "version": "1.0.0", + "description": "", + "main": "miniprogram_dist/index.js", + "scripts": { + "dev": "gulp dev --develop", + "watch": "gulp watch --develop --watch", + "build": "gulp", + "dist": "npm run build", + "clean-dev": "gulp clean --develop", + "clean": "gulp clean", + "test": "jest ./test/* --silent --bail", + "coverage": "jest ./test/* --coverage --bail", + "lint": "eslint \"src/**/*.js\"", + "lint-tools": "eslint \"tools/**/*.js\" --rule \"import/no-extraneous-dependencies: false\"" + }, + "miniprogram": "miniprogram_dist", + "jest": { + "testEnvironment": "jsdom", + "testURL": "https://jest.test", + "collectCoverageFrom": [ + "src/**/*.js" + ], + "moduleDirectories": [ + "node_modules", + "src" + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/IceApriler/miniprogram-picker.git" + }, + "author": "wechat-miniprogram", + "license": "MIT", + "devDependencies": { + "babel-core": "^6.26.3", + "babel-loader": "^7.1.5", + "babel-plugin-module-resolver": "^3.1.1", + "babel-preset-env": "^1.7.0", + "colors": "^1.3.1", + "eslint": "^5.3.0", + "eslint-config-airbnb-base": "13.1.0", + "eslint-loader": "^2.1.0", + "eslint-plugin-import": "^2.14.0", + "eslint-plugin-node": "^7.0.1", + "eslint-plugin-promise": "^3.8.0", + "gulp": "^4.0.0", + "gulp-clean": "^0.4.0", + "gulp-if": "^2.0.2", + "gulp-install": "^1.1.0", + "gulp-less": "^3.5.0", + "gulp-rename": "^1.4.0", + "gulp-sourcemaps": "^2.6.4", + "jest": "^23.5.0", + "miniprogram-simulate": "^0.1.3", + "through2": "^2.0.3", + "webpack": "^4.16.5", + "webpack-node-externals": "^1.7.2" + }, + "dependencies": {} +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..933dd81 --- /dev/null +++ b/src/index.js @@ -0,0 +1,22 @@ +Component({ + properties: { + prop: { + type: String, + value: 'index.properties' + }, + }, + data: { + flag: false, + }, + lifetimes: { + attached() { + wx.getSystemInfo({ + success: res => { + this.setData({ + flag: true, + }) + } + }) + } + } +}) diff --git a/src/index.json b/src/index.json new file mode 100644 index 0000000..e8cfaaf --- /dev/null +++ b/src/index.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/src/index.wxml b/src/index.wxml new file mode 100644 index 0000000..7d4c23c --- /dev/null +++ b/src/index.wxml @@ -0,0 +1 @@ +{{prop}}-{{flag}} diff --git a/src/index.wxss b/src/index.wxss new file mode 100644 index 0000000..38bf189 --- /dev/null +++ b/src/index.wxss @@ -0,0 +1,3 @@ +.index { + color: green; +} diff --git a/test/index.test.js b/test/index.test.js new file mode 100644 index 0000000..1e787bf --- /dev/null +++ b/test/index.test.js @@ -0,0 +1,15 @@ +const _ = require('./utils') + +test('render', async () => { + const componentId = _.load('index', 'comp') + const component = _.render(componentId, {prop: 'index.test.properties'}) + + const parent = document.createElement('parent-wrapper') + component.attach(parent) + + expect(_.match(component.dom, 'index.test.properties-false')).toBe(true) + + await _.sleep(10) + + expect(_.match(component.dom, 'index.test.properties-true')).toBe(true) +}) diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 0000000..a56c560 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,22 @@ +const path = require('path') +const simulate = require('miniprogram-simulate') + +const config = require('../tools/config') + +const srcPath = config.srcPath +const oldLoad = simulate.load +simulate.load = function (componentPath, ...args) { + componentPath = path.join(srcPath, componentPath) + return oldLoad(componentPath, ...args) +} + +module.exports = simulate + +// adjust the simulated wx api +const oldGetSystemInfoSync = global.wx.getSystemInfoSync +global.wx.getSystemInfoSync = function() { + const res = oldGetSystemInfoSync() + res.SDKVersion = '2.4.1' + + return res +} diff --git a/test/wx.test.js b/test/wx.test.js new file mode 100644 index 0000000..0209e56 --- /dev/null +++ b/test/wx.test.js @@ -0,0 +1,18 @@ +const _ = require('./utils') + +test('wx.getSystemInfo', async () => { + wx.getSystemInfo({ + success(res) { + expect(res.errMsg).toBe('getSystemInfo:ok') + }, + complete(res) { + expect(res.errMsg).toBe('getSystemInfo:ok') + }, + }) +}) + +test('wx.getSystemInfoSync', async () => { + const info = wx.getSystemInfoSync() + expect(info.SDKVersion).toBe('2.4.1') + expect(info.version).toBe('6.6.3') +}) diff --git a/tools/build.js b/tools/build.js new file mode 100644 index 0000000..6a6634c --- /dev/null +++ b/tools/build.js @@ -0,0 +1,318 @@ +const path = require('path') + +const gulp = require('gulp') +const clean = require('gulp-clean') +const less = require('gulp-less') +const rename = require('gulp-rename') +const gulpif = require('gulp-if') +const sourcemaps = require('gulp-sourcemaps') +const webpack = require('webpack') +const gulpInstall = require('gulp-install') + +const config = require('./config') +const checkComponents = require('./checkcomponents') +const _ = require('./utils') + +const wxssConfig = config.wxss || {} +const srcPath = config.srcPath +const distPath = config.distPath + +/** + * get wxss stream + */ +function wxss(wxssFileList) { + if (!wxssFileList.length) return false + + return gulp.src(wxssFileList, {cwd: srcPath, base: srcPath}) + .pipe(gulpif(wxssConfig.less && wxssConfig.sourcemap, sourcemaps.init())) + .pipe(gulpif(wxssConfig.less, less({paths: [srcPath]}))) + .pipe(rename({extname: '.wxss'})) + .pipe(gulpif(wxssConfig.less && wxssConfig.sourcemap, sourcemaps.write('./'))) + .pipe(_.logger(wxssConfig.less ? 'generate' : undefined)) + .pipe(gulp.dest(distPath)) +} + +/** + * get js stream + */ +function js(jsFileMap, scope) { + const webpackConfig = config.webpack + const webpackCallback = (err, stats) => { + if (!err) { + // eslint-disable-next-line no-console + console.log(stats.toString({ + assets: true, + cached: false, + colors: true, + children: false, + errors: true, + warnings: true, + version: true, + modules: false, + publicPath: true, + })) + } else { + // eslint-disable-next-line no-console + console.log(err) + } + } + + webpackConfig.entry = jsFileMap + webpackConfig.output.path = distPath + + if (scope.webpackWatcher) { + scope.webpackWatcher.close() + scope.webpackWatcher = null + } + + if (config.isWatch) { + scope.webpackWatcher = webpack(webpackConfig).watch({ + ignored: /node_modules/, + }, webpackCallback) + } else { + webpack(webpackConfig).run(webpackCallback) + } +} + +/** + * copy file + */ +function copy(copyFileList) { + if (!copyFileList.length) return false + + return gulp.src(copyFileList, {cwd: srcPath, base: srcPath}) + .pipe(_.logger()) + .pipe(gulp.dest(distPath)) +} + +/** + * install packages + */ +function install() { + return gulp.series(async () => { + const demoDist = config.demoDist + const demoPackageJsonPath = path.join(demoDist, 'package.json') + const packageJson = _.readJson(path.resolve(__dirname, '../package.json')) + const dependencies = packageJson.dependencies || {} + + await _.writeFile(demoPackageJsonPath, JSON.stringify({dependencies}, null, '\t')) // write dev demo's package.json + }, () => { + const demoDist = config.demoDist + const demoPackageJsonPath = path.join(demoDist, 'package.json') + + return gulp.src(demoPackageJsonPath) + .pipe(gulpInstall({production: true})) + }) +} + +class BuildTask { + constructor(id, entry) { + if (!entry) return + + this.id = id + this.entries = Array.isArray(config.entry) ? config.entry : [config.entry] + this.copyList = Array.isArray(config.copy) ? config.copy : [] + this.componentListMap = {} + this.cachedComponentListMap = {} + + this.init() + } + + init() { + const id = this.id + + /** + * clean the dist folder + */ + gulp.task(`${id}-clean-dist`, () => gulp.src(distPath, {read: false, allowEmpty: true}).pipe(clean())) + + /** + * copy demo to the dev folder + */ + let isDemoExists = false + gulp.task(`${id}-demo`, gulp.series(async () => { + const demoDist = config.demoDist + + isDemoExists = await _.checkFileExists(path.join(demoDist, 'project.config.json')) + }, done => { + if (!isDemoExists) { + const demoSrc = config.demoSrc + const demoDist = config.demoDist + + return gulp.src('**/*', {cwd: demoSrc, base: demoSrc}) + .pipe(gulp.dest(demoDist)) + } + + return done() + })) + + /** + * install packages for dev + */ + gulp.task(`${id}-install`, install()) + + /** + * check custom components + */ + gulp.task(`${id}-component-check`, async () => { + const entries = this.entries + const mergeComponentListMap = {} + for (let i = 0, len = entries.length; i < len; i++) { + let entry = entries[i] + entry = path.join(srcPath, `${entry}.json`) + // eslint-disable-next-line no-await-in-loop + const newComponentListMap = await checkComponents(entry) + + _.merge(mergeComponentListMap, newComponentListMap) + } + + this.cachedComponentListMap = this.componentListMap + this.componentListMap = mergeComponentListMap + }) + + /** + * write json to the dist folder + */ + gulp.task(`${id}-component-json`, done => { + const jsonFileList = this.componentListMap.jsonFileList + + if (jsonFileList && jsonFileList.length) { + return copy(this.componentListMap.jsonFileList) + } + + return done() + }) + + /** + * copy wxml to the dist folder + */ + gulp.task(`${id}-component-wxml`, done => { + const wxmlFileList = this.componentListMap.wxmlFileList + + if (wxmlFileList && + wxmlFileList.length && + !_.compareArray(this.cachedComponentListMap.wxmlFileList, wxmlFileList)) { + return copy(wxmlFileList) + } + + return done() + }) + + /** + * generate wxss to the dist folder + */ + gulp.task(`${id}-component-wxss`, done => { + const wxssFileList = this.componentListMap.wxssFileList + + if (wxssFileList && + wxssFileList.length && + !_.compareArray(this.cachedComponentListMap.wxssFileList, wxssFileList)) { + return wxss(wxssFileList, srcPath, distPath) + } + + return done() + }) + + /** + * generate js to the dist folder + */ + gulp.task(`${id}-component-js`, done => { + const jsFileList = this.componentListMap.jsFileList + + if (jsFileList && + jsFileList.length && + !_.compareArray(this.cachedComponentListMap.jsFileList, jsFileList)) { + js(this.componentListMap.jsFileMap, this) + } + + return done() + }) + + /** + * copy resources to dist folder + */ + gulp.task(`${id}-copy`, gulp.parallel(done => { + const copyList = this.copyList + const copyFileList = copyList.map(dir => path.join(dir, '**/*.!(wxss)')) + + if (copyFileList.length) return copy(copyFileList) + + return done() + }, done => { + const copyList = this.copyList + const copyFileList = copyList.map(dir => path.join(dir, '**/*.wxss')) + + if (copyFileList.length) return wxss(copyFileList, srcPath, distPath) + + return done() + })) + + /** + * watch json + */ + gulp.task(`${id}-watch-json`, () => gulp.watch(this.componentListMap.jsonFileList, {cwd: srcPath, base: srcPath}, gulp.series(`${id}-component-check`, gulp.parallel(`${id}-component-wxml`, `${id}-component-wxss`, `${id}-component-js`, `${id}-component-json`)))) + + /** + * watch wxml + */ + gulp.task(`${id}-watch-wxml`, () => { + this.cachedComponentListMap.wxmlFileList = null + return gulp.watch(this.componentListMap.wxmlFileList, {cwd: srcPath, base: srcPath}, gulp.series(`${id}-component-wxml`)) + }) + + /** + * watch wxss + */ + gulp.task(`${id}-watch-wxss`, () => { + this.cachedComponentListMap.wxssFileList = null + return gulp.watch('**/*.wxss', {cwd: srcPath, base: srcPath}, gulp.series(`${id}-component-wxss`)) + }) + + /** + * watch resources + */ + gulp.task(`${id}-watch-copy`, () => { + const copyList = this.copyList + const copyFileList = copyList.map(dir => path.join(dir, '**/*')) + const watchCallback = filePath => copy([filePath]) + + return gulp.watch(copyFileList, {cwd: srcPath, base: srcPath}) + .on('change', watchCallback) + .on('add', watchCallback) + .on('unlink', watchCallback) + }) + + /** + * watch demo + */ + gulp.task(`${id}-watch-demo`, () => { + const demoSrc = config.demoSrc + const demoDist = config.demoDist + const watchCallback = filePath => gulp.src(filePath, {cwd: demoSrc, base: demoSrc}) + .pipe(gulp.dest(demoDist)) + + return gulp.watch('**/*', {cwd: demoSrc, base: demoSrc}) + .on('change', watchCallback) + .on('add', watchCallback) + .on('unlink', watchCallback) + }) + + /** + * watch installed packages + */ + gulp.task(`${id}-watch-install`, () => gulp.watch(path.resolve(__dirname, '../package.json'), install())) + + /** + * build custom component + */ + gulp.task(`${id}-build`, gulp.series(`${id}-clean-dist`, `${id}-component-check`, gulp.parallel(`${id}-component-wxml`, `${id}-component-wxss`, `${id}-component-js`, `${id}-component-json`, `${id}-copy`))) + + gulp.task(`${id}-watch`, gulp.series(`${id}-build`, `${id}-demo`, `${id}-install`, gulp.parallel(`${id}-watch-wxml`, `${id}-watch-wxss`, `${id}-watch-json`, `${id}-watch-copy`, `${id}-watch-install`, `${id}-watch-demo`))) + + gulp.task(`${id}-dev`, gulp.series(`${id}-build`, `${id}-demo`, `${id}-install`)) + + gulp.task(`${id}-default`, gulp.series(`${id}-build`)) + } +} + +module.exports = BuildTask diff --git a/tools/checkcomponents.js b/tools/checkcomponents.js new file mode 100644 index 0000000..53f3766 --- /dev/null +++ b/tools/checkcomponents.js @@ -0,0 +1,87 @@ +const path = require('path') + +const _ = require('./utils') +const config = require('./config') + +const srcPath = config.srcPath + +/** + * get json path's info + */ +function getJsonPathInfo(jsonPath) { + const dirPath = path.dirname(jsonPath) + const fileName = path.basename(jsonPath, '.json') + const relative = path.relative(srcPath, dirPath) + const fileBase = path.join(relative, fileName) + + return { + dirPath, fileName, relative, fileBase + } +} + +/** + * check included components + */ +const checkProps = ['usingComponents', 'componentGenerics'] +async function checkIncludedComponents(jsonPath, componentListMap) { + const json = _.readJson(jsonPath) + if (!json) throw new Error(`json is not valid: "${jsonPath}"`) + + const {dirPath, fileName, fileBase} = getJsonPathInfo(jsonPath) + + for (let i = 0, len = checkProps.length; i < len; i++) { + const checkProp = checkProps[i] + const checkPropValue = json[checkProp] || {} + const keys = Object.keys(checkPropValue) + + for (let j = 0, jlen = keys.length; j < jlen; j++) { + const key = keys[j] + let value = typeof checkPropValue[key] === 'object' ? checkPropValue[key].default : checkPropValue[key] + if (!value) continue + + value = _.transformPath(value, path.sep) + + // check relative path + const componentPath = `${path.join(dirPath, value)}.json` + // eslint-disable-next-line no-await-in-loop + const isExists = await _.checkFileExists(componentPath) + if (isExists) { + // eslint-disable-next-line no-await-in-loop + await checkIncludedComponents(componentPath, componentListMap) + } + } + } + + // checked + componentListMap.wxmlFileList.push(`${fileBase}.wxml`) + componentListMap.wxssFileList.push(`${fileBase}.wxss`) + componentListMap.jsonFileList.push(`${fileBase}.json`) + componentListMap.jsFileList.push(`${fileBase}.js`) + + componentListMap.jsFileMap[fileBase] = `${path.join(dirPath, fileName)}.js` +} + +module.exports = async function (entry) { + const componentListMap = { + wxmlFileList: [], + wxssFileList: [], + jsonFileList: [], + jsFileList: [], + + jsFileMap: {}, // for webpack entry + } + + const isExists = await _.checkFileExists(entry) + if (!isExists) { + const {dirPath, fileName, fileBase} = getJsonPathInfo(entry) + + componentListMap.jsFileList.push(`${fileBase}.js`) + componentListMap.jsFileMap[fileBase] = `${path.join(dirPath, fileName)}.js` + + return componentListMap + } + + await checkIncludedComponents(entry, componentListMap) + + return componentListMap +} diff --git a/tools/config.js b/tools/config.js new file mode 100644 index 0000000..da089f2 --- /dev/null +++ b/tools/config.js @@ -0,0 +1,67 @@ +const path = require('path') + +const webpack = require('webpack') +const nodeExternals = require('webpack-node-externals') + +const isDev = process.argv.indexOf('--develop') >= 0 +const isWatch = process.argv.indexOf('--watch') >= 0 +const demoSrc = path.resolve(__dirname, './demo') +const demoDist = path.resolve(__dirname, '../miniprogram_dev') +const src = path.resolve(__dirname, '../src') +const dev = path.join(demoDist, 'components') +const dist = path.resolve(__dirname, '../miniprogram_dist') + +module.exports = { + entry: ['index'], + + isDev, + isWatch, + srcPath: src, + distPath: isDev ? dev : dist, + + demoSrc, + demoDist, + + wxss: { + less: false, // compile wxss with less + sourcemap: false, // source map for less + }, + + webpack: { + mode: 'production', + output: { + filename: '[name].js', + libraryTarget: 'commonjs2', + }, + target: 'node', + externals: [nodeExternals()], // ignore node_modules + module: { + rules: [{ + test: /\.js$/i, + use: [ + 'babel-loader', + 'eslint-loader' + ], + exclude: /node_modules/ + }], + }, + resolve: { + modules: [src, 'node_modules'], + extensions: ['.js', '.json'], + }, + plugins: [ + new webpack.DefinePlugin({}), + new webpack.optimize.LimitChunkCountPlugin({maxChunks: 1}), + ], + optimization: { + minimize: false, + }, + // devtool: 'nosources-source-map', // source map for js + performance: { + hints: 'warning', + assetFilter: assetFilename => assetFilename.endsWith('.js') + } + }, + + copy: ['./wxml', './wxss', './wxs', './images'], // will copy to dist +} diff --git a/tools/demo/app.js b/tools/demo/app.js new file mode 100644 index 0000000..6241c06 --- /dev/null +++ b/tools/demo/app.js @@ -0,0 +1 @@ +App({}) diff --git a/tools/demo/app.json b/tools/demo/app.json new file mode 100644 index 0000000..4bc8a6f --- /dev/null +++ b/tools/demo/app.json @@ -0,0 +1,11 @@ +{ + "pages":[ + "pages/index/index" + ], + "window":{ + "backgroundTextStyle":"light", + "navigationBarBackgroundColor": "#fff", + "navigationBarTitleText": "WeChat", + "navigationBarTextStyle":"black" + } +} diff --git a/tools/demo/app.wxss b/tools/demo/app.wxss new file mode 100644 index 0000000..e69de29 diff --git a/tools/demo/package.json b/tools/demo/package.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/tools/demo/package.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/tools/demo/pages/index/index.js b/tools/demo/pages/index/index.js new file mode 100644 index 0000000..ba76804 --- /dev/null +++ b/tools/demo/pages/index/index.js @@ -0,0 +1 @@ +Page({}) diff --git a/tools/demo/pages/index/index.json b/tools/demo/pages/index/index.json new file mode 100644 index 0000000..fda2d24 --- /dev/null +++ b/tools/demo/pages/index/index.json @@ -0,0 +1,5 @@ +{ + "usingComponents": { + "comp": "../../components/index" + } +} \ No newline at end of file diff --git a/tools/demo/pages/index/index.wxml b/tools/demo/pages/index/index.wxml new file mode 100644 index 0000000..ea63c1e --- /dev/null +++ b/tools/demo/pages/index/index.wxml @@ -0,0 +1 @@ + diff --git a/tools/demo/pages/index/index.wxss b/tools/demo/pages/index/index.wxss new file mode 100644 index 0000000..e69de29 diff --git a/tools/demo/project.config.json b/tools/demo/project.config.json new file mode 100644 index 0000000..2bdb6ce --- /dev/null +++ b/tools/demo/project.config.json @@ -0,0 +1,37 @@ +{ + "description": "项目配置文件。", + "packOptions": { + "ignore": [] + }, + "setting": { + "urlCheck": true, + "es6": true, + "postcss": true, + "minified": true, + "newFeature": true, + "nodeModules": true + }, + "compileType": "miniprogram", + "libVersion": "2.2.3", + "appid": "", + "projectname": "miniprogram-demo", + "isGameTourist": false, + "condition": { + "search": { + "current": -1, + "list": [] + }, + "conversation": { + "current": -1, + "list": [] + }, + "game": { + "currentL": -1, + "list": [] + }, + "miniprogram": { + "current": -1, + "list": [] + } + } +} \ No newline at end of file diff --git a/tools/utils.js b/tools/utils.js new file mode 100644 index 0000000..360a461 --- /dev/null +++ b/tools/utils.js @@ -0,0 +1,213 @@ +const fs = require('fs') +const path = require('path') + +// eslint-disable-next-line no-unused-vars +const colors = require('colors') +const through = require('through2') + +/** + * async function wrapper + */ +function wrap(func, scope) { + return function (...args) { + if (args.length) { + const temp = args.pop() + if (typeof temp !== 'function') { + args.push(temp) + } + } + + return new Promise(function (resolve, reject) { + args.push(function (err, data) { + if (err) reject(err) + else resolve(data) + }) + + func.apply((scope || null), args) + }) + } +} + +const accessSync = wrap(fs.access) +const statSync = wrap(fs.stat) +const renameSync = wrap(fs.rename) +const mkdirSync = wrap(fs.mkdir) +const readFileSync = wrap(fs.readFile) +const writeFileSync = wrap(fs.writeFile) + +/** + * transform path segment separator + */ +function transformPath(filePath, sep = '/') { + return filePath.replace(/[\\/]/g, sep) +} + +/** + * check file exists + */ +async function checkFileExists(filePath) { + try { + await accessSync(filePath) + return true + } catch (err) { + return false + } +} + +/** + * create folder + */ +async function recursiveMkdir(dirPath) { + const prevDirPath = path.dirname(dirPath) + try { + await accessSync(prevDirPath) + } catch (err) { + // prevDirPath is not exist + await recursiveMkdir(prevDirPath) + } + + try { + await accessSync(dirPath) + + const stat = await statSync(dirPath) + if (stat && !stat.isDirectory()) { + // dirPath already exists but is not a directory + await renameSync(dirPath, `${dirPath}.bak`) // rename to a file with the suffix ending in '.bak' + await mkdirSync(dirPath) + } + } catch (err) { + // dirPath is not exist + await mkdirSync(dirPath) + } +} + +/** + * read json + */ +function readJson(filePath) { + try { + // eslint-disable-next-line import/no-dynamic-require + const content = require(filePath) + delete require.cache[require.resolve(filePath)] + return content + } catch (err) { + return null + } +} + +/** + * read file + */ +async function readFile(filePath) { + try { + return await readFileSync(filePath, 'utf8') + } catch (err) { + // eslint-disable-next-line no-console + return console.error(err) + } +} + +/** + * write file + */ +async function writeFile(filePath, data) { + try { + await recursiveMkdir(path.dirname(filePath)) + return await writeFileSync(filePath, data, 'utf8') + } catch (err) { + // eslint-disable-next-line no-console + return console.error(err) + } +} + +/** + * time format + */ +function format(time, reg) { + const date = typeof time === 'string' ? new Date(time) : time + const map = {} + map.yyyy = date.getFullYear() + map.yy = ('' + map.yyyy).substr(2) + map.M = date.getMonth() + 1 + map.MM = (map.M < 10 ? '0' : '') + map.M + map.d = date.getDate() + map.dd = (map.d < 10 ? '0' : '') + map.d + map.H = date.getHours() + map.HH = (map.H < 10 ? '0' : '') + map.H + map.m = date.getMinutes() + map.mm = (map.m < 10 ? '0' : '') + map.m + map.s = date.getSeconds() + map.ss = (map.s < 10 ? '0' : '') + map.s + + return reg.replace(/\byyyy|yy|MM|M|dd|d|HH|H|mm|m|ss|s\b/g, $1 => map[$1]) +} + +/** + * logger plugin + */ +function logger(action = 'copy') { + return through.obj(function (file, enc, cb) { + const type = path.extname(file.path).slice(1).toLowerCase() + + // eslint-disable-next-line no-console + console.log(`[${format(new Date(), 'yyyy-MM-dd HH:mm:ss').grey}] [${action.green} ${type.green}] ${'=>'.cyan} ${file.path}`) + + this.push(file) + cb() + }) +} + +/** + * compare arrays + */ +function compareArray(arr1, arr2) { + if (!Array.isArray(arr1) || !Array.isArray(arr2)) return false + if (arr1.length !== arr2.length) return false + + for (let i = 0, len = arr1.length; i < len; i++) { + if (arr1[i] !== arr2[i]) return false + } + + return true +} + +/** + * merge two object + */ +function merge(obj1, obj2) { + Object.keys(obj2).forEach(key => { + if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) { + obj1[key] = obj1[key].concat(obj2[key]) + } else if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') { + obj1[key] = Object.assign(obj1[key], obj2[key]) + } else { + obj1[key] = obj2[key] + } + }) + + return obj1 +} + +/** + * get random id + */ +let seed = +new Date() +function getId() { + return ++seed +} + +module.exports = { + wrap, + transformPath, + + checkFileExists, + readJson, + readFile, + writeFile, + + logger, + format, + compareArray, + merge, + getId, +}