Repository: wechat-miniprogram/kbone-template-react
Branch: master
Commit: 5f9ae76b4002
Files: 15
Total size: 16.2 KB
Directory structure:
gitextract_ok9soqir/
├── .babelrc
├── .gitignore
├── LICENSE
├── README.md
├── build/
│ ├── miniprogram.config.js
│ ├── webpack.base.config.js
│ ├── webpack.dev.config.js
│ ├── webpack.mp.config.js
│ └── webpack.prod.config.js
├── index.html
├── package.json
└── src/
├── components/
│ └── counter/
│ ├── index.css
│ └── index.jsx
├── index.jsx
└── log.jsx
================================================
FILE CONTENTS
================================================
================================================
FILE: .babelrc
================================================
{
"presets": [
"env",
"stage-3",
"react"
],
"plugins": [
"transform-runtime"
]
}
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
# others
.idea
.DS_Store
dist
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 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.
================================================
FILE: README.md
================================================
# react-kbone
使用 react 多端开发(小程序和Web),基于 [kbone](https://github.com/Tencent/kbone) 的 element 和 render。
## 特性
* 一键接入,立即使用
* 支持完整 JSX 语法,任意位置任意方式书写 JSX
## 一套语法多端运行
```jsx
function Counter() {
const [count, setCount] = useState(0)
return (
setCount(count - 1)}>-
{count}
setCount(count + 1)}>+
跳转
)
}
function clickHandle() {
if ('undefined' != typeof wx && wx.getSystemInfoSync) {
wx.navigateTo({
url: '../log/index?id=1',
})
} else {
location.href = 'log.html'
}
}
export default Counter
```
## 快速开始
```
npx kbone-cli init my-app
cd my-app
npm run mp // 开发小程序
npm run build:mp // 构建小程序
npm run web // 开发 web
npm run build // 构建 web
```
## 目录说明
```
├─ dist
│ ├─ mp // 微信开发者工具指向的目录,用于生产环境
│ ├─ web // web 编译出的文件,用于生产环境
├─ build // 构建相关
├─ src
│ ├─ assets
│ ├─ components // 存放所有组件
│ ├─ log.jsx // 入口文件,会 build 成 log.html
│ └─ index.jsx // 入口文件,会 build 成 index.html
```
## 注意事项
react 并没有提供根组件实例的销毁方法(如 vue.$destroy),所以在多页应用中页面关闭时不会触发该页面组件的 componentWillUnmount 钩子。开发者可自行监听 wxunload 或 beforeunload 事件来进行页面的销毁工作,比如调用 render 方法渲染一个空节点,强行触发页面组件的 componentWillUnmount 钩子。
## 谁在使用 kbone?
## License
MIT
================================================
FILE: build/miniprogram.config.js
================================================
/**
* 配置参考:https://wechat-miniprogram.github.io/kbone/docs/config/
*/
module.exports = {
origin: 'https://test.miniprogram.com',
entry: '/',
router: {
home: [
'/(home|index)?',
'/index.html',
'/test/(home|index)',
],
other: [
'/test/list/:id',
'/test/detail/:id',
],
},
redirect: {
notFound: 'home',
accessDenied: 'home',
},
generate: {
autoBuildNpm: 'npm',
},
app: {
navigationBarTitleText: 'miniprogram-project',
},
appExtraConfig: {
sitemapLocation: 'sitemap.json',
},
global: {},
pages: {},
optimization: {
domSubTreeLevel: 10,
elementMultiplexing: true,
textMultiplexing: true,
commentMultiplexing: true,
domExtendMultiplexing: true,
styleValueReduce: 5000,
attrValueReduce: 5000,
},
projectConfig: {
projectname: 'kbone-template-react',
appid: '',
},
}
================================================
FILE: build/webpack.base.config.js
================================================
const path = require('path')
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
index: path.resolve(__dirname, '../src/index.jsx'),
log: path.resolve(__dirname, '../src/log.jsx'),
},
output: {
path: path.resolve(__dirname, '../dist/web'),
filename: '[name].js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.[t|j]sx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]',
},
},
],
},
resolve: {
extensions: ['*', '.js', '.jsx', '.json']
},
}
================================================
FILE: build/webpack.dev.config.js
================================================
const webpack = require('webpack')
const { merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.config')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const portfinder = require('portfinder')
const htmlPluginList = Object.keys(baseWebpackConfig.entry).map(name => {
return new HtmlWebpackPlugin({
filename: `${name}.html`,
template: 'index.html',
inject: true,
chunks: [name],
})
})
const devWebpackConfig = merge(baseWebpackConfig, {
mode: 'development',
devServer: {
historyApiFallback: {
rewrites: [{from: /.*/, to: '/index.html'}],
},
hot: true,
compress: true,
host: process.env.HOST || 'localhost',
port: +process.env.PORT || 8080,
open: true, // 自动打开浏览器
client: {
logging: 'warn',
overlay: { // 展示全屏报错
warnings: false,
errors: true
},
},
static: {
publicPath: '/',
},
proxy: {},
},
watchOptions: {
poll: false,
},
devtool: 'cheap-module-eval-source-map',
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"development"',
},
}),
new webpack.HotModuleReplacementPlugin(),
...htmlPluginList,
],
})
module.exports = new Promise((resolve, reject) => {
portfinder.basePort = +process.env.PORT || 8080
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
devWebpackConfig.devServer.port = port
resolve(devWebpackConfig)
}
})
})
================================================
FILE: build/webpack.mp.config.js
================================================
const path = require('path')
const webpack = require('webpack')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const MpPlugin = require('mp-webpack-plugin')
const isOptimize = false // 是否压缩业务代码,开发者工具可能无法完美支持业务代码使用到的 es 特性,建议自己做代码压缩
module.exports = {
mode: 'production',
entry: {
index: path.resolve(__dirname, '../src/index.jsx'),
log: path.resolve(__dirname, '../src/log.jsx'),
},
output: {
path: path.resolve(__dirname, '../dist/mp/common'), // 放到小程序代码目录中的 common 目录下
filename: '[name].js', // 必需字段,不能修改
library: 'createApp', // 必需字段,不能修改
libraryExport: 'default', // 必需字段,不能修改
libraryTarget: 'window', // 必需字段,不能修改
},
target: 'web', // 必需字段,不能修改
optimization: {
runtimeChunk: false, // 必需字段,不能修改
splitChunks: {
// 代码分隔配置,不建议修改
chunks: 'all',
minSize: 1000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 100,
maxInitialRequests: 100,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
minimizer: isOptimize
? [
// 压缩CSS
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.(css|wxss)$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: [
'default',
{
discardComments: {
removeAll: true,
},
minifySelectors: false, // 因为 wxss 编译器不支持 .some>:first-child 这样格式的代码,所以暂时禁掉这个
},
],
},
canPrint: false,
}),
// 压缩 js
new TerserPlugin({
test: /\.js(\?.*)?$/i,
parallel: true,
}),
]
: [],
},
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.[t|j]sx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]',
},
},
],
},
resolve: {
extensions: ['*', '.js', '.jsx', '.json'],
},
plugins: [
new webpack.DefinePlugin({
'process.env.isMiniprogram': process.env.isMiniprogram, // 注入环境变量,用于业务代码判断
}),
new MiniCssExtractPlugin({
filename: '[name].wxss',
}),
new MpPlugin(require('./miniprogram.config')),
],
}
================================================
FILE: build/webpack.prod.config.js
================================================
const path = require('path')
const webpack = require('webpack')
const { merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.config')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const htmlPluginList = Object.keys(baseWebpackConfig.entry).map(name => {
return new HtmlWebpackPlugin({
filename: path.resolve(__dirname, `../dist/web/${name}.html`),
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
},
chunks: [name],
})
})
const webpackConfig = merge(baseWebpackConfig, {
mode: 'production',
output: {
path: path.resolve(__dirname, '../dist/web'),
filename: path.posix.join('static', 'js/[name].[chunkhash].js'),
chunkFilename: path.posix.join('static', 'js/[id].[chunkhash].js'),
},
optimization: {
splitChunks: {
// 代码分割配置
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
minimizer: [
// 压缩CSS
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: [
'default',
{
discardComments: {
removeAll: true,
},
},
],
},
canPrint: false,
}),
// 压缩 js
new TerserPlugin({
test: /\.js(\?.*)?$/i,
parallel: true,
}),
],
},
devtool: false,
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"',
},
}),
// 分离 css 文件
new MiniCssExtractPlugin({
filename: path.posix.join('static', 'css/[name].[hash].css'),
}),
...htmlPluginList,
// 当 vendor 模块没有改变时,保证模块 id 不变
new webpack.HashedModuleIdsPlugin(),
],
})
module.exports = webpackConfig
================================================
FILE: index.html
================================================
react
================================================
FILE: package.json
================================================
{
"name": "react-kbone",
"version": "0.0.1",
"description": "",
"author": "wechat-miniprogram",
"keywords": [
"react",
"kbone",
"mp"
],
"scripts": {
"start": "npm run mp",
"web": "cross-env NODE_ENV=development webpack-dev-server --progress --config build/webpack.dev.config.js",
"mp": "rimraf dist/mp/common && cross-env NODE_ENV=development webpack --config build/webpack.mp.config.js --watch --progress",
"build": "rimraf dist/web && cross-env NODE_ENV=production webpack --config build/webpack.prod.config.js --progress",
"build:mp": "rimraf dist/mp/common && cross-env NODE_ENV=production webpack --config build/webpack.mp.config.js --progress"
},
"dependencies": {
"react": "^16.9.0",
"react-dom": "^16.9.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"devDependencies": {
"@webpack-cli/serve": "^1.6.1",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-3": "^6.24.1",
"cross-env": "^5.0.5",
"css-loader": "^0.28.7",
"file-loader": "^1.1.4",
"html-webpack-plugin": "^4.5.2",
"mini-css-extract-plugin": "^0.5.0",
"mp-webpack-plugin": "latest",
"optimize-css-assets-webpack-plugin": "^5.0.8",
"portfinder": "^1.0.28",
"rimraf": "^2.7.1",
"style-loader": "^2.0.0",
"stylehacks": "^4.0.3",
"terser-webpack-plugin": "^4.2.3",
"webpack": "^4.29.6",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4",
"webpack-merge": "^5.8.0"
},
"license": "MIT"
}
================================================
FILE: src/components/counter/index.css
================================================
span{
color: red;
}
================================================
FILE: src/components/counter/index.jsx
================================================
import React, { useState } from 'react'
import './index.css'
function Counter() {
const [count, setCount] = useState(0)
return (
setCount(count - 1)}>-
{count}
setCount(count + 1)}>+
跳转
)
}
function clickHandle() {
if ('undefined' != typeof wx && wx.getSystemInfoSync) {
wx.navigateTo({
url: '../log/index?id=1',
})
} else {
location.href = 'log.html'
}
}
export default Counter
================================================
FILE: src/index.jsx
================================================
import React from 'react'
import ReactDOM from 'react-dom'
import Counter from './components/counter'
export default function createApp() {
const container = document.createElement('div')
container.id = 'app'
document.body.appendChild(container)
ReactDOM.render( , container)
}
;('undefined' != typeof wx && wx.getSystemInfoSync) || createApp()
================================================
FILE: src/log.jsx
================================================
import React from 'react'
import ReactDOM from 'react-dom'
export default function createApp() {
const container = document.createElement('div')
container.id = 'app'
document.body.appendChild(container)
ReactDOM.render(我是log页面
, container)
}
;('undefined' != typeof wx && wx.getSystemInfoSync) || createApp()