diff --git a/package.json b/package.json
index 365b58f..b554c47 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"start": "jest test --watch",
"test": "jest test",
"test:webpack": "cd test && webpack",
+ "test:webpack:ts": "cd test && TEST_EXT=ts webpack",
"prebuild": "rimraf ./lib && mkdirp ./lib",
"build:watch": "babel src -o lib/index.js -w",
"build": "babel src -o lib/index.js",
diff --git a/src/index.js b/src/index.js
index f2c279c..7cc55c4 100644
--- a/src/index.js
+++ b/src/index.js
@@ -13,395 +13,409 @@ import NodeSourcePlugin from 'webpack/lib/node/NodeSourcePlugin';
const { CommonsChunkPlugin } = optimize;
const deprecated = function deprecated(obj, key, adapter, explain) {
- if (deprecated.warned.has(key)) { return; }
- const val = obj[key];
- if (typeof val === 'undefined') { return; }
- deprecated.warned.add(key);
- adapter(val);
- console.warn('[WXAppPlugin]', explain);
+ if (deprecated.warned.has(key)) { return; }
+ const val = obj[key];
+ if (typeof val === 'undefined') { return; }
+ deprecated.warned.add(key);
+ adapter(val);
+ console.warn('[WXAppPlugin]', explain);
};
deprecated.warned = new Set();
const stripExt = (path) => {
- const { dir, name } = parse(path);
- return join(dir, name);
+ const { dir, name } = parse(path);
+ return join(dir, name);
};
const miniProgramTarget = (compiler) => {
- const { options } = compiler;
- compiler.apply(
- new JsonpTemplatePlugin(options.output),
- new FunctionModulePlugin(options.output),
- new NodeSourcePlugin(options.node),
- new LoaderTargetPlugin('web'),
- );
+ const { options } = compiler;
+ compiler.apply(
+ new JsonpTemplatePlugin(options.output),
+ new FunctionModulePlugin(options.output),
+ new NodeSourcePlugin(options.node),
+ new LoaderTargetPlugin('web'),
+ );
};
export const Targets = {
- Wechat(compiler) { return miniProgramTarget(compiler); },
- Alipay(compiler) { return miniProgramTarget(compiler); },
+ Wechat(compiler) { return miniProgramTarget(compiler); },
+ Alipay(compiler) { return miniProgramTarget(compiler); },
};
export default class WXAppPlugin {
- constructor(options = {}) {
- this.options = defaults(options || {}, {
- clear: true,
- include: [],
- exclude: [],
- dot: false, // Include `.dot` files
- extensions: ['.js'],
- commonModuleName: 'common.js',
- enforceTarget: true,
- assetsChunkName: '__assets_chunk_name__',
- // base: undefined,
- });
-
- deprecated(
- this.options,
- 'scriptExt',
- (val) => this.options.extensions.unshift(val),
- 'Option `scriptExt` is deprecated. Please use `extensions` instead',
- );
-
- deprecated(
- this.options,
- 'forceTarge',
- (val) => (this.options.enforceTarget = val),
- 'Option `forceTarge` is deprecated. Please use `enforceTarget` instead',
- );
-
- this.options.extensions = uniq([...this.options.extensions, '.js']);
- this.options.include = [].concat(this.options.include);
- this.options.exclude = [].concat(this.options.exclude);
- }
-
- apply(compiler) {
- const { clear } = this.options;
- let isFirst = true;
-
- this.enforceTarget(compiler);
-
- compiler.plugin('run', this.try(async (compiler) => {
- await this.run(compiler);
- }));
-
- compiler.plugin('watch-run', this.try(async (compiler) => {
- await this.run(compiler.compiler);
- }));
-
- compiler.plugin('emit', this.try(async (compilation) => {
- if (clear && isFirst) {
- isFirst = false;
- await this.clear(compilation);
- }
-
- await this.toEmitTabBarIcons(compilation);
- }));
-
- compiler.plugin('after-emit', this.try(async (compilation) => {
- await this.toAddTabBarIconsDependencies(compilation);
- }));
- }
-
- try = (handler) => async (arg, callback) => {
- try {
- await handler(arg);
- callback();
- }
- catch (err) {
- callback(err);
- }
- };
-
- enforceTarget(compiler) {
- const { enforceTarget } = this.options;
- const { options } = compiler;
-
- if (enforceTarget) {
- const { target } = options;
- if (target !== Targets.Wechat && target !== Targets.Alipay) {
- options.target = Targets.Wechat;
- }
- if (!options.node || options.node.global) {
- options.node = options.node || {};
- options.node.global = false;
- }
- }
- }
-
- getBase(compiler) {
- const { base, extensions } = this.options;
- if (base) { return resolve(base); }
-
- const { options: compilerOptions } = compiler;
- const { context, entry } = compilerOptions;
-
- const getEntryFromCompiler = () => {
- if (typeof entry === 'string') {
- return entry;
- }
-
- const extRegExpStr = extensions
- .map((ext) => ext.replace(/\./, '\\.'))
- .map((ext) => `(${ext})`)
- .join('|')
- ;
-
- const appJSRegExp = new RegExp(`\\bapp(${extRegExpStr})?$`);
- const findAppJS = (arr) => arr.find((path) => appJSRegExp.test(path));
-
- if (Array.isArray(entry)) {
- return findAppJS(entry);
- }
- if (typeof entry === 'object') {
-
- for (const key in entry) {
- if (!entry.hasOwnProperty(key)) { continue; }
-
- const val = entry[key];
- if (typeof val === 'string') {
- return val;
- }
- if (Array.isArray(val)) {
- return findAppJS(val);
- }
- }
- }
- };
-
- const entryFromCompiler = getEntryFromCompiler();
-
- if (entryFromCompiler) {
- return dirname(entryFromCompiler);
- }
-
- return context;
- }
-
- async getTabBarIcons(tabBar) {
- const tabBarIcons = new Set();
- const tabBarList = tabBar.list || [];
- for (const tabBarItem of tabBarList) {
- if (tabBarItem.iconPath) {
- tabBarIcons.add(tabBarItem.iconPath);
- }
- if (tabBarItem.selectedIconPath) {
- tabBarIcons.add(tabBarItem.selectedIconPath);
- }
- }
-
- this.tabBarIcons = tabBarIcons;
- }
-
- async toEmitTabBarIcons(compilation) {
- const emitIcons = [];
- this.tabBarIcons.forEach((iconPath) => {
- const iconSrc = resolve(this.base, iconPath);
- const toEmitIcon = async () => {
- const iconStat = await stat(iconSrc);
- const iconSource = await readFile(iconSrc);
- compilation.assets[iconPath] = {
- size: () => iconStat.size,
- source: () => iconSource,
- };
- };
- emitIcons.push(toEmitIcon());
- });
- await Promise.all(emitIcons);
- }
-
- toAddTabBarIconsDependencies(compilation) {
- const { fileDependencies } = compilation;
- this.tabBarIcons.forEach((iconPath) => {
- if (!~fileDependencies.indexOf(iconPath)) {
- fileDependencies.push(iconPath);
- }
- });
- }
-
- async getEntryResource() {
- const appJSONFile = resolve(this.base, 'app.json');
- const { pages = [], tabBar = {} } = await readJson(appJSONFile);
-
- const components = new Set();
- for (const page of pages) {
- await this.getComponents(components, resolve(this.base, page));
- }
-
- this.getTabBarIcons(tabBar);
- return ['app', ...pages, ...components];
- }
-
- async getComponents(components, instance) {
- const { usingComponents = {} } =
- await readJson(`${instance}.json`).catch(
- err => err && err.code !== 'ENOENT' && console.error(err)
- ) || {};
- const componentBase = parse(instance).dir;
- for (const relativeComponent of values(usingComponents)) {
- if (relativeComponent.indexOf('plugin://') === 0) continue
- const component = resolve(componentBase, relativeComponent);
- if (!components.has(component)) {
- components.add(relative(this.base, component));
- await this.getComponents(components, component);
- }
- }
- }
-
- getFullScriptPath(path) {
- const { base, options: { extensions } } = this;
- for (const ext of extensions) {
- const fullPath = resolve(base, path + ext);
- if (existsSync(fullPath)) { return fullPath; }
- }
- }
-
- async clear(compilation) {
- const { path } = compilation.options.output;
- await remove(path);
- }
-
- addEntries(compiler, entries, chunkName) {
- compiler.apply(new MultiEntryPlugin(this.base, entries, chunkName));
- }
-
- async compileAssets(compiler) {
- const {
- options: {
- include,
- exclude,
- dot,
- assetsChunkName,
- extensions,
- },
- entryResources,
- } = this;
-
- compiler.plugin('compilation', (compilation) => {
- compilation.plugin('before-chunk-assets', () => {
- const assetsChunkIndex = compilation.chunks.findIndex(({ name }) =>
- name === assetsChunkName
- );
- if (assetsChunkIndex > -1) {
- compilation.chunks.splice(assetsChunkIndex, 1);
- }
- });
- });
-
- const patterns = entryResources
- .map((resource) => `${resource}.*`)
- .concat(include)
- ;
-
- const entries = await globby(patterns, {
- cwd: this.base,
- nodir: true,
- realpath: true,
- ignore: [
- ...extensions.map((ext) => `**/*${ext}`),
- ...exclude,
- ],
- dot,
- });
-
- this.addEntries(compiler, entries, assetsChunkName);
- }
-
- getChunkResourceRegExp() {
- if (this._chunkResourceRegex) { return this._chunkResourceRegex; }
-
- const { options: { extensions } } = this;
- const exts = extensions
- .map((ext) => ext.replace(/\./g, '\\.'))
- .map((ext) => `(${ext}$)`)
- .join('|')
- ;
- return new RegExp(exts);
- }
-
- applyCommonsChunk(compiler) {
- const {
- options: { commonModuleName },
- entryResources,
- } = this;
-
- const scripts = entryResources.map(::this.getFullScriptPath);
-
- compiler.apply(new CommonsChunkPlugin({
- name: stripExt(commonModuleName),
- minChunks: ({ resource }) => {
- if (resource) {
- const regExp = this.getChunkResourceRegExp();
- return regExp.test(resource) && scripts.indexOf(resource) < 0;
- }
- return false;
- },
- }));
- }
-
- addScriptEntry(compiler, entry, name) {
- compiler.plugin('make', (compilation, callback) => {
- const dep = SingleEntryPlugin.createDependency(entry, name);
- compilation.addEntry(this.base, dep, name, callback);
- });
- }
-
- compileScripts(compiler) {
- this.applyCommonsChunk(compiler);
- this.entryResources
- .filter((resource) => resource !== 'app')
- .forEach((resource) => {
- const fullPath = this.getFullScriptPath(resource);
- this.addScriptEntry(compiler, fullPath, resource);
- })
- ;
- }
-
- toModifyTemplate(compilation) {
- const { commonModuleName } = this.options;
- const { target } = compilation.options;
- const commonChunkName = stripExt(commonModuleName);
- const globalVar = target.name === 'Alipay' ? 'my' : 'wx';
-
- // inject chunk entries
- compilation.chunkTemplate.plugin('render', (core, { name }) => {
- if (this.entryResources.indexOf(name) >= 0) {
- const relativePath = relative(dirname(name), `./${commonModuleName}`);
- const posixPath = relativePath.replace(/\\/g, '/');
- const source = core.source();
-
- // eslint-disable-next-line max-len
- const injectContent = `; function webpackJsonp() { require("./${posixPath}"); ${globalVar}.webpackJsonp.apply(null, arguments); }`;
-
- if (source.indexOf(injectContent) < 0) {
- const concatSource = new ConcatSource(core);
- concatSource.add(injectContent);
- return concatSource;
- }
- }
- return core;
- });
-
- // replace `window` to `global` in common chunk
- compilation.mainTemplate.plugin('bootstrap', (source, chunk) => {
- const windowRegExp = new RegExp('window', 'g');
- if (chunk.name === commonChunkName) {
- return source.replace(windowRegExp, globalVar);
- }
- return source;
- });
-
- // override `require.ensure()`
- compilation.mainTemplate.plugin('require-ensure', () =>
- 'throw new Error("Not chunk loading available");'
- );
- }
-
- async run(compiler) {
- this.base = this.getBase(compiler);
- this.entryResources = await this.getEntryResource();
- compiler.plugin('compilation', ::this.toModifyTemplate);
- this.compileScripts(compiler);
- await this.compileAssets(compiler);
- }
+ constructor(options = {}) {
+ this.options = defaults(options || {}, {
+ clear: true,
+ include: [],
+ exclude: [],
+ dot: false, // Include `.dot` files
+ extensions: ['.js'],
+ commonModuleName: 'common.js',
+ enforceTarget: true,
+ assetsChunkName: '__assets_chunk_name__',
+ // base: undefined,
+ });
+
+ deprecated(
+ this.options,
+ 'scriptExt',
+ (val) => this.options.extensions.unshift(val),
+ 'Option `scriptExt` is deprecated. Please use `extensions` instead',
+ );
+
+ deprecated(
+ this.options,
+ 'forceTarge',
+ (val) => (this.options.enforceTarget = val),
+ 'Option `forceTarge` is deprecated. Please use `enforceTarget` instead',
+ );
+
+ this.options.extensions = uniq([...this.options.extensions, '.js']);
+ this.options.include = [].concat(this.options.include);
+ this.options.exclude = [].concat(this.options.exclude);
+ }
+
+ apply(compiler) {
+ const { clear } = this.options;
+ let isFirst = true;
+
+ this.enforceTarget(compiler);
+
+ compiler.plugin('run', this.try(async (compiler) => {
+ await this.run(compiler);
+ }));
+
+ compiler.plugin('watch-run', this.try(async (compiler) => {
+ await this.run(compiler.compiler);
+ }));
+
+ compiler.plugin('emit', this.try(async (compilation) => {
+ if (clear && isFirst) {
+ isFirst = false;
+ await this.clear(compilation);
+ }
+
+ await this.toEmitTabBarIcons(compilation);
+ }));
+
+ compiler.plugin('after-emit', this.try(async (compilation) => {
+ await this.toAddTabBarIconsDependencies(compilation);
+ }));
+ }
+
+ try = (handler) => async (arg, callback) => {
+ try {
+ await handler(arg);
+ callback();
+ }
+ catch (err) {
+ callback(err);
+ }
+ };
+
+ enforceTarget(compiler) {
+ const { enforceTarget } = this.options;
+ const { options } = compiler;
+
+ if (enforceTarget) {
+ const { target } = options;
+ if (target !== Targets.Wechat && target !== Targets.Alipay) {
+ options.target = Targets.Wechat;
+ }
+ if (!options.node || options.node.global) {
+ options.node = options.node || {};
+ options.node.global = false;
+ }
+ }
+ }
+
+ getBase(compiler) {
+ const { base, extensions } = this.options;
+ if (base) { return resolve(base); }
+
+ const { options: compilerOptions } = compiler;
+ const { context, entry } = compilerOptions;
+
+ const getEntryFromCompiler = () => {
+ if (typeof entry === 'string') {
+ return entry;
+ }
+
+ const extRegExpStr = extensions
+ .map((ext) => ext.replace(/\./, '\\.'))
+ .map((ext) => `(${ext})`)
+ .join('|')
+ ;
+
+ const appJSRegExp = new RegExp(`\\bapp(${extRegExpStr})?$`);
+ const findAppJS = (arr) => arr.find((path) => appJSRegExp.test(path));
+
+ if (Array.isArray(entry)) {
+ return findAppJS(entry);
+ }
+ if (typeof entry === 'object') {
+
+ for (const key in entry) {
+ if (!entry.hasOwnProperty(key)) { continue; }
+
+ const val = entry[key];
+ if (typeof val === 'string') {
+ return val;
+ }
+ if (Array.isArray(val)) {
+ return findAppJS(val);
+ }
+ }
+ }
+ };
+
+ const entryFromCompiler = getEntryFromCompiler();
+
+ if (entryFromCompiler) {
+ return dirname(entryFromCompiler);
+ }
+
+ return context;
+ }
+
+ async getTabBarIcons(tabBar) {
+ const tabBarIcons = new Set();
+ const tabBarList = tabBar.list || [];
+ for (const tabBarItem of tabBarList) {
+ if (tabBarItem.iconPath) {
+ tabBarIcons.add(tabBarItem.iconPath);
+ }
+ if (tabBarItem.selectedIconPath) {
+ tabBarIcons.add(tabBarItem.selectedIconPath);
+ }
+ }
+
+ this.tabBarIcons = tabBarIcons;
+ }
+
+ async toEmitTabBarIcons(compilation) {
+ const emitIcons = [];
+ this.tabBarIcons.forEach((iconPath) => {
+ const iconSrc = resolve(this.base, iconPath);
+ const toEmitIcon = async () => {
+ const iconStat = await stat(iconSrc);
+ const iconSource = await readFile(iconSrc);
+ compilation.assets[iconPath] = {
+ size: () => iconStat.size,
+ source: () => iconSource,
+ };
+ };
+ emitIcons.push(toEmitIcon());
+ });
+ await Promise.all(emitIcons);
+ }
+
+ toAddTabBarIconsDependencies(compilation) {
+ const { fileDependencies } = compilation;
+ this.tabBarIcons.forEach((iconPath) => {
+ if (!~fileDependencies.indexOf(iconPath)) {
+ fileDependencies.push(iconPath);
+ }
+ });
+ }
+
+ async getEntryResource() {
+ const appJSONFile = resolve(this.base, 'app.json');
+ const { pages = [], subPackages = [], tabBar = {} } = await readJson(appJSONFile);
+
+ const components = new Set();
+ for (const page of pages) {
+ await this.getComponents(components, resolve(this.base, page));
+ }
+
+ for (const subPackage of subPackages) {
+ const { root, pages = [] } = subPackage;
+
+ await Promise.all(pages.map(async page =>
+ await this.getComponents(components, resolve(this.base, join(root, page)))
+ ));
+ }
+
+ this.getTabBarIcons(tabBar);
+
+ return [
+ 'app',
+ ...pages,
+ ...[].concat(...subPackages.map(v => v.pages.map(w => join(v.root, w)))),
+ ...components
+ ];
+ }
+
+ async getComponents(components, instance) {
+ const { usingComponents = {} } =
+ await readJson(`${instance}.json`).catch(
+ err => err && err.code !== 'ENOENT' && console.error(err)
+ ) || {};
+ const componentBase = parse(instance).dir;
+ for (const relativeComponent of values(usingComponents)) {
+ if (relativeComponent.indexOf('plugin://') === 0) continue
+ const component = resolve(componentBase, relativeComponent);
+ if (!components.has(component)) {
+ components.add(relative(this.base, component));
+ await this.getComponents(components, component);
+ }
+ }
+ }
+
+ getFullScriptPath(path) {
+ const { base, options: { extensions } } = this;
+ for (const ext of extensions) {
+ const fullPath = resolve(base, path + ext);
+ if (existsSync(fullPath)) { return fullPath; }
+ }
+ }
+
+ async clear(compilation) {
+ const { path } = compilation.options.output;
+ await remove(path);
+ }
+
+ addEntries(compiler, entries, chunkName) {
+ compiler.apply(new MultiEntryPlugin(this.base, entries, chunkName));
+ }
+
+ async compileAssets(compiler) {
+ const {
+ options: {
+ include,
+ exclude,
+ dot,
+ assetsChunkName,
+ extensions,
+ },
+ entryResources,
+ } = this;
+
+ compiler.plugin('compilation', (compilation) => {
+ compilation.plugin('before-chunk-assets', () => {
+ const assetsChunkIndex = compilation.chunks.findIndex(({ name }) =>
+ name === assetsChunkName
+ );
+ if (assetsChunkIndex > -1) {
+ compilation.chunks.splice(assetsChunkIndex, 1);
+ }
+ });
+ });
+
+ const patterns = entryResources
+ .map((resource) => `${resource}.*`)
+ .concat(include)
+ ;
+
+ const entries = await globby(patterns, {
+ cwd: this.base,
+ nodir: true,
+ realpath: true,
+ ignore: [
+ ...extensions.map((ext) => `**/*${ext}`),
+ ...exclude,
+ ],
+ dot,
+ });
+
+ this.addEntries(compiler, entries, assetsChunkName);
+ }
+
+ getChunkResourceRegExp() {
+ if (this._chunkResourceRegex) { return this._chunkResourceRegex; }
+
+ const { options: { extensions } } = this;
+ const exts = extensions
+ .map((ext) => ext.replace(/\./g, '\\.'))
+ .map((ext) => `(${ext}$)`)
+ .join('|')
+ ;
+ return new RegExp(exts);
+ }
+
+ applyCommonsChunk(compiler) {
+ const {
+ options: { commonModuleName },
+ entryResources,
+ } = this;
+
+ const scripts = entryResources.map(::this.getFullScriptPath);
+
+ compiler.apply(new CommonsChunkPlugin({
+ name: stripExt(commonModuleName),
+ minChunks: ({ resource }) => {
+ if (resource) {
+ const regExp = this.getChunkResourceRegExp();
+ return regExp.test(resource) && scripts.indexOf(resource) < 0;
+ }
+ return false;
+ },
+ }));
+ }
+
+ addScriptEntry(compiler, entry, name) {
+ compiler.plugin('make', (compilation, callback) => {
+ const dep = SingleEntryPlugin.createDependency(entry, name);
+ compilation.addEntry(this.base, dep, name, callback);
+ });
+ }
+
+ compileScripts(compiler) {
+ this.applyCommonsChunk(compiler);
+ this.entryResources
+ .filter((resource) => resource !== 'app')
+ .forEach((resource) => {
+ const fullPath = this.getFullScriptPath(resource);
+ this.addScriptEntry(compiler, fullPath, resource);
+ })
+ ;
+ }
+
+ toModifyTemplate(compilation) {
+ const { commonModuleName } = this.options;
+ const { target } = compilation.options;
+ const commonChunkName = stripExt(commonModuleName);
+ const globalVar = target.name === 'Alipay' ? 'my' : 'wx';
+
+ // inject chunk entries
+ compilation.chunkTemplate.plugin('render', (core, { name }) => {
+ if (this.entryResources.indexOf(name) >= 0) {
+ const relativePath = relative(dirname(name), `./${commonModuleName}`);
+ const posixPath = relativePath.replace(/\\/g, '/');
+ const source = core.source();
+
+ // eslint-disable-next-line max-len
+ const injectContent = `; function webpackJsonp() { require("./${posixPath}"); ${globalVar}.webpackJsonp.apply(null, arguments); }`;
+
+ if (source.indexOf(injectContent) < 0) {
+ const concatSource = new ConcatSource(core);
+ concatSource.add(injectContent);
+ return concatSource;
+ }
+ }
+ return core;
+ });
+
+ // replace `window` to `global` in common chunk
+ compilation.mainTemplate.plugin('bootstrap', (source, chunk) => {
+ const windowRegExp = new RegExp('window', 'g');
+ if (chunk.name === commonChunkName) {
+ return source.replace(windowRegExp, globalVar);
+ }
+ return source;
+ });
+
+ // override `require.ensure()`
+ compilation.mainTemplate.plugin('require-ensure', () =>
+ 'throw new Error("Not chunk loading available");'
+ );
+ }
+
+ async run(compiler) {
+ this.base = this.getBase(compiler);
+ this.entryResources = await this.getEntryResource();
+ compiler.plugin('compilation', ::this.toModifyTemplate);
+ this.compileScripts(compiler);
+ await this.compileAssets(compiler);
+ }
}
diff --git a/test/src/js/app.json b/test/src/js/app.json
index 8ef173d..12ffc49 100644
--- a/test/src/js/app.json
+++ b/test/src/js/app.json
@@ -16,6 +16,15 @@
"text": "日志"
}]
},
+ "subPackages": [
+ {
+ "root": "pages/product",
+ "pages": [
+ "productDetail",
+ "productList"
+ ]
+ }
+ ],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
diff --git a/test/src/js/pages/index/index.js b/test/src/js/pages/index/index.js
index d0be0c4..0b52d56 100644
--- a/test/src/js/pages/index/index.js
+++ b/test/src/js/pages/index/index.js
@@ -17,6 +17,11 @@ Page({
url: '../logs/logs',
});
},
+ goToSubList() {
+ wx.navigateTo({
+ url: '../product/productList',
+ });
+ },
onLoad() {
// await delay();
diff --git a/test/src/js/pages/index/index.wxml b/test/src/js/pages/index/index.wxml
index 022ad3b..6fa58f8 100644
--- a/test/src/js/pages/index/index.wxml
+++ b/test/src/js/pages/index/index.wxml
@@ -6,5 +6,6 @@
{{motto}}
+ go to subPackages
diff --git a/test/src/js/pages/product/productDetail.js b/test/src/js/pages/product/productDetail.js
new file mode 100644
index 0000000..b349c0b
--- /dev/null
+++ b/test/src/js/pages/product/productDetail.js
@@ -0,0 +1,15 @@
+
+import { formatTime } from '../../utils/util';
+
+Page({
+ data: {
+ logs: [],
+ },
+ onLoad() {
+ this.setData({
+ logs: (wx.getStorageSync('logs') || []).map(function (log) {
+ return formatTime(new Date(log));
+ }),
+ });
+ }
+});
diff --git a/test/src/js/pages/product/productDetail.json b/test/src/js/pages/product/productDetail.json
new file mode 100644
index 0000000..69bae8d
--- /dev/null
+++ b/test/src/js/pages/product/productDetail.json
@@ -0,0 +1,7 @@
+{
+ "navigationBarTitleText": "分包明细",
+ "usingComponents": {
+ "log-component": "../../components/log-component/log-component"
+ }
+ }
+
\ No newline at end of file
diff --git a/test/src/js/pages/product/productDetail.wxml b/test/src/js/pages/product/productDetail.wxml
new file mode 100644
index 0000000..0e2e86f
--- /dev/null
+++ b/test/src/js/pages/product/productDetail.wxml
@@ -0,0 +1,6 @@
+
+
+
+ {{index + 1}}. {{log}}
+
+
diff --git a/test/src/js/pages/product/productDetail.wxss b/test/src/js/pages/product/productDetail.wxss
new file mode 100644
index 0000000..e69de29
diff --git a/test/src/js/pages/product/productList.js b/test/src/js/pages/product/productList.js
new file mode 100644
index 0000000..f927edb
--- /dev/null
+++ b/test/src/js/pages/product/productList.js
@@ -0,0 +1,36 @@
+
+// import { flow } from 'lodash';
+
+// const delay = (t = 0) => new Promise((resolve) => setTimeout(resolve, t));
+
+//获取应用实例
+const app = getApp(); // eslint-disable-line no-undef
+
+Page({
+ data: {
+ motto: 'Hello List',
+ userInfo: {},
+ },
+ //事件处理函数
+ bindViewTap() {
+ wx.navigateTo({
+ url: './productDetail',
+ });
+ },
+ onLoad() {
+
+ // await delay();
+
+ // const log = flow(() => {
+ // console.log('onLoad');
+ // });
+
+ // log();
+
+ //调用应用实例的方法获取全局数据
+ app.getUserInfo((userInfo) => {
+ //更新数据
+ this.setData({ userInfo });
+ });
+ },
+});
diff --git a/test/src/js/pages/product/productList.json b/test/src/js/pages/product/productList.json
new file mode 100644
index 0000000..19af1ed
--- /dev/null
+++ b/test/src/js/pages/product/productList.json
@@ -0,0 +1,6 @@
+{
+ "usingComponents": {
+ "index-component": "../../components/index-component/index-component"
+ }
+ }
+
\ No newline at end of file
diff --git a/test/src/js/pages/product/productList.wxml b/test/src/js/pages/product/productList.wxml
new file mode 100644
index 0000000..7c35a94
--- /dev/null
+++ b/test/src/js/pages/product/productList.wxml
@@ -0,0 +1,35 @@
+
+
+
+ click me and go to detail page
+
+ {{userInfo.nickName}}
+
+
+ {{motto}}
+
+
+
+
+
+
+ click me and go to detail page
+
+ {{userInfo.nickName}}
+
+
+ {{motto}}
+
+
+
+
+
+
+ click me and go to detail page
+
+ {{userInfo.nickName}}
+
+
+ {{motto}}
+
+
diff --git a/test/src/js/pages/product/productList.wxss b/test/src/js/pages/product/productList.wxss
new file mode 100644
index 0000000..e69de29
diff --git a/test/src/ts/app.json b/test/src/ts/app.json
index 8ef173d..12ffc49 100644
--- a/test/src/ts/app.json
+++ b/test/src/ts/app.json
@@ -16,6 +16,15 @@
"text": "日志"
}]
},
+ "subPackages": [
+ {
+ "root": "pages/product",
+ "pages": [
+ "productDetail",
+ "productList"
+ ]
+ }
+ ],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
diff --git a/test/src/ts/pages/index/index.ts b/test/src/ts/pages/index/index.ts
index d0be0c4..0b52d56 100644
--- a/test/src/ts/pages/index/index.ts
+++ b/test/src/ts/pages/index/index.ts
@@ -17,6 +17,11 @@ Page({
url: '../logs/logs',
});
},
+ goToSubList() {
+ wx.navigateTo({
+ url: '../product/productList',
+ });
+ },
onLoad() {
// await delay();
diff --git a/test/src/ts/pages/index/index.wxml b/test/src/ts/pages/index/index.wxml
index 022ad3b..6fa58f8 100644
--- a/test/src/ts/pages/index/index.wxml
+++ b/test/src/ts/pages/index/index.wxml
@@ -6,5 +6,6 @@
{{motto}}
+ go to subPackages
diff --git a/test/src/ts/pages/product/productDetail.json b/test/src/ts/pages/product/productDetail.json
new file mode 100644
index 0000000..69bae8d
--- /dev/null
+++ b/test/src/ts/pages/product/productDetail.json
@@ -0,0 +1,7 @@
+{
+ "navigationBarTitleText": "分包明细",
+ "usingComponents": {
+ "log-component": "../../components/log-component/log-component"
+ }
+ }
+
\ No newline at end of file
diff --git a/test/src/ts/pages/product/productDetail.ts b/test/src/ts/pages/product/productDetail.ts
new file mode 100644
index 0000000..b349c0b
--- /dev/null
+++ b/test/src/ts/pages/product/productDetail.ts
@@ -0,0 +1,15 @@
+
+import { formatTime } from '../../utils/util';
+
+Page({
+ data: {
+ logs: [],
+ },
+ onLoad() {
+ this.setData({
+ logs: (wx.getStorageSync('logs') || []).map(function (log) {
+ return formatTime(new Date(log));
+ }),
+ });
+ }
+});
diff --git a/test/src/ts/pages/product/productDetail.wxml b/test/src/ts/pages/product/productDetail.wxml
new file mode 100644
index 0000000..0e2e86f
--- /dev/null
+++ b/test/src/ts/pages/product/productDetail.wxml
@@ -0,0 +1,6 @@
+
+
+
+ {{index + 1}}. {{log}}
+
+
diff --git a/test/src/ts/pages/product/productDetail.wxss b/test/src/ts/pages/product/productDetail.wxss
new file mode 100644
index 0000000..e69de29
diff --git a/test/src/ts/pages/product/productList.json b/test/src/ts/pages/product/productList.json
new file mode 100644
index 0000000..19af1ed
--- /dev/null
+++ b/test/src/ts/pages/product/productList.json
@@ -0,0 +1,6 @@
+{
+ "usingComponents": {
+ "index-component": "../../components/index-component/index-component"
+ }
+ }
+
\ No newline at end of file
diff --git a/test/src/ts/pages/product/productList.ts b/test/src/ts/pages/product/productList.ts
new file mode 100644
index 0000000..f927edb
--- /dev/null
+++ b/test/src/ts/pages/product/productList.ts
@@ -0,0 +1,36 @@
+
+// import { flow } from 'lodash';
+
+// const delay = (t = 0) => new Promise((resolve) => setTimeout(resolve, t));
+
+//获取应用实例
+const app = getApp(); // eslint-disable-line no-undef
+
+Page({
+ data: {
+ motto: 'Hello List',
+ userInfo: {},
+ },
+ //事件处理函数
+ bindViewTap() {
+ wx.navigateTo({
+ url: './productDetail',
+ });
+ },
+ onLoad() {
+
+ // await delay();
+
+ // const log = flow(() => {
+ // console.log('onLoad');
+ // });
+
+ // log();
+
+ //调用应用实例的方法获取全局数据
+ app.getUserInfo((userInfo) => {
+ //更新数据
+ this.setData({ userInfo });
+ });
+ },
+});
diff --git a/test/src/ts/pages/product/productList.wxml b/test/src/ts/pages/product/productList.wxml
new file mode 100644
index 0000000..7c35a94
--- /dev/null
+++ b/test/src/ts/pages/product/productList.wxml
@@ -0,0 +1,35 @@
+
+
+
+ click me and go to detail page
+
+ {{userInfo.nickName}}
+
+
+ {{motto}}
+
+
+
+
+
+
+ click me and go to detail page
+
+ {{userInfo.nickName}}
+
+
+ {{motto}}
+
+
+
+
+
+
+ click me and go to detail page
+
+ {{userInfo.nickName}}
+
+
+ {{motto}}
+
+
diff --git a/test/src/ts/pages/product/productList.wxss b/test/src/ts/pages/product/productList.wxss
new file mode 100644
index 0000000..e69de29