├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .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 ├── App.vue ├── common │ ├── Footer.vue │ ├── Header.vue │ ├── KboneUI.vue │ └── Web.vue ├── detail │ └── Index.vue ├── home │ ├── Index.vue │ └── web.js ├── list │ └── Index.vue ├── main.js ├── mp │ ├── home │ │ └── main.mp.js │ └── other │ │ └── main.mp.js ├── router │ └── index.js └── store │ ├── actions.js │ ├── index.js │ └── mutations.js └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime"], 12 | "env": { 13 | "test": { 14 | "presets": ["env", "stage-2"], 15 | "plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /dist/ 3 | /*.js 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parserOptions: { 6 | parser: 'babel-eslint' 7 | }, 8 | env: { 9 | browser: true, 10 | }, 11 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 12 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 13 | extends: ['plugin:vue/essential', 'airbnb-base'], 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'vue' 17 | ], 18 | // check if imports actually resolve 19 | settings: { 20 | 'import/resolver': { 21 | webpack: { 22 | config: 'build/webpack.base.config.js' 23 | } 24 | } 25 | }, 26 | rules: { 27 | // disallow reassignment of function parameters 28 | // disallow parameter object manipulation except for specific exclusions 29 | 'no-param-reassign': ['error', { 30 | props: true, 31 | ignorePropertyModificationsFor: [ 32 | 'state', // for vuex state 33 | 'acc', // for reduce accumulators 34 | 'e' // for e.returnvalue 35 | ] 36 | }], 37 | // allow optionalDependencies 38 | 'import/no-extraneous-dependencies': ['error', { 39 | optionalDependencies: ['test/unit/index.js'] 40 | }], 41 | // allow debugger during development 42 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 43 | // others 44 | 'no-console': 'off', 45 | 'semi': [ 46 | 'error', 47 | 'never' 48 | ], 49 | 'no-new': 'off', 50 | 'comma-dangle': [ 51 | 'error', 52 | 'only-multiline' 53 | ], 54 | 'import/no-webpack-loader-syntax': 'off', 55 | 'import/first': 'off', 56 | 'linebreak-style': ['off', 'windows'], 57 | }, 58 | 'globals': { 59 | 'window': true, 60 | 'document': true, 61 | 'App': true, 62 | 'Page': true, 63 | 'Component': true, 64 | 'Behavior': true, 65 | 'wx': true, 66 | 'getCurrentPages': true, 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # others 64 | .idea 65 | .DS_Store 66 | package-lock.json 67 | dist 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 wechat-miniprogram 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 | # vue-kbone-ui 2 | 3 | 使用 vue 多端开发(小程序和Web),基于 [kbone](https://github.com/wechat-miniprogram/kbone) 的 element 和 render。 4 | 5 | ## 特性 6 | 7 | * 一键接入,立即使用 8 | * 支持更完整的 vue 语法及特性 9 | * webpack、es6、babel、hot reload、cli、vue-router、vuex,你想要的都有 10 | 11 | ## 开发 12 | 13 | * Web 端:直接浏览器访问 localhost:8080/ 即可看到效果。 14 | 15 | ``` 16 | npm run web 17 | ``` 18 | 19 | * 小程序端:使用开发者工具打开 dist/mp 目录即可。 20 | 21 | ``` 22 | npm run mp 23 | ``` 24 | 25 | ## 构建 26 | 27 | * Web 端:构建完成会生成 dist/web 目录 28 | 29 | ``` 30 | npm run build 31 | ``` 32 | 33 | * 小程序端:构建完成会生成 dist/mp 目录 34 | 35 | ``` 36 | npm run build:mp 37 | ``` 38 | 39 | ## 小程序端打开 40 | 41 | 需要先进入 dist/mp 目录执行 `npm install` 安装相关的依赖包,然后用开发者工具打开 dist/mp 目录后再进行 npm 构建(关于 npm 构建可[点此查看官方文档](https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html))。 42 | 43 | ## 目录说明 44 | 45 | 此模板 Web 端使用单入口,通过 vue-router + 动态 import 的方式来运行;小程序端则按照业务分拆成多个页面,同属一个业务的页面则通过 vue-router 来组织。 46 | 47 | ``` 48 | ├─ build 49 | │ ├─ miniprogram.config.js // mp-webpack-plugin 配置 50 | │ ├─ webpack.base.config.js // Web 端构建基础配置 51 | │ ├─ webpack.dev.config.js // Web 端构建开发环境配置 52 | │ ├─ webpack.mp.config.js // 小程序端构建配置 53 | │ └─ webpack.prod.config.js // Web 端构建生产环境配置 54 | ├─ dist 55 | │ ├─ mp // 小程序端目标代码目录,使用微信开发者工具打开,用于生产环境 56 | │ └─ web // web 端编译出的文件,用于生产环境 57 | ├─ src 58 | │ ├─ common // 通用组件 59 | │ ├─ mp // 小程序端入口目录 60 | │ │ ├─ home // 小程序端 home 页面 61 | │ │ │ └─ main.mp.js // 小程序端入口文件 62 | │ │ └─ other // 小程序端 other 页面 63 | │ │ └─ main.mp.js // 小程序端入口文件 64 | │ ├─ detail // detail 页面 65 | │ ├─ home // home 页面 66 | │ ├─ list // list 页面 67 | │ ├─ router // vue-router 路由定义 68 | │ ├─ store // vuex 相关目录 69 | │ ├─ App.vue // Web 端入口主视图 70 | │ └─ main.js // Web 端入口文件 71 | └─ index.html // Web 端入口模板 72 | ``` 73 | 74 | ## 其他说明 75 | 76 | 如果要使用 ts,则在 vue 的 script 标签上加上 `lang="ts"`,具体可参考 src/list/Index.vue。如果要使用 reduce-loader,就不能使用 ts,因为 ts 目前没有支持内联 loader。 77 | 78 | ## License 79 | 80 | MIT 81 | -------------------------------------------------------------------------------- /build/miniprogram.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 配置参考:https://wechat-miniprogram.github.io/kbone/docs/config/ 3 | */ 4 | 5 | module.exports = { 6 | origin: 'https://test.miniprogram.com', 7 | entry: '/', 8 | router: { 9 | home: [ 10 | '/(home|index)?', 11 | '/index.html', 12 | '/test/(home|index)', 13 | ], 14 | other: [ 15 | '/test/list/:id', 16 | '/test/detail/:id', 17 | ], 18 | }, 19 | redirect: { 20 | notFound: 'home', 21 | accessDenied: 'home', 22 | }, 23 | generate: { 24 | autoBuildNpm: 'npm', 25 | appWxss: 'display', 26 | weui: true, 27 | }, 28 | app: { 29 | backgroundTextStyle: 'dark', 30 | navigationBarTextStyle: 'white', 31 | navigationBarTitleText: 'kbone', 32 | }, 33 | appExtraConfig: { 34 | sitemapLocation: 'sitemap.json', 35 | }, 36 | global: { 37 | share: true, 38 | windowScroll: false, 39 | backgroundColor: '#F7F7F7', 40 | }, 41 | pages: {}, 42 | optimization: { 43 | domSubTreeLevel: 10, 44 | 45 | elementMultiplexing: true, 46 | textMultiplexing: true, 47 | commentMultiplexing: true, 48 | domExtendMultiplexing: true, 49 | 50 | styleValueReduce: 5000, 51 | attrValueReduce: 5000, 52 | }, 53 | projectConfig: { 54 | projectname: 'kbone-template-vue-ui', 55 | appid: 'wx14c7c4cd189644a1', 56 | }, 57 | } 58 | -------------------------------------------------------------------------------- /build/webpack.base.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const eslintFriendlyFormatter = require('eslint-friendly-formatter') 3 | 4 | module.exports = { 5 | context: path.resolve(__dirname, '../'), 6 | entry: { 7 | app: path.resolve(__dirname, '../src/main.js'), 8 | }, 9 | output: { 10 | path: path.resolve(__dirname, '../dist/web'), 11 | filename: '[name].js', 12 | publicPath: '/', 13 | }, 14 | module: { 15 | rules: [ 16 | // eslint 17 | { 18 | test: /\.(js|vue)$/, 19 | loader: 'eslint-loader', 20 | enforce: 'pre', 21 | include: [path.resolve(__dirname, '../src')], 22 | options: { 23 | formatter: eslintFriendlyFormatter, 24 | emitWarning: true, 25 | }, 26 | }, 27 | // vue 28 | { 29 | test: /\.vue$/, 30 | use: [{ 31 | loader: 'thread-loader', 32 | }, { 33 | loader: 'vue-loader', 34 | options: { 35 | compilerOptions: { 36 | preserveWhitespace: false, 37 | }, 38 | }, 39 | }], 40 | }, 41 | // ts 42 | { 43 | test: /\.tsx?$/, 44 | exclude: /node_modules/, 45 | use: [{ 46 | loader: 'thread-loader', 47 | }, { 48 | loader: 'babel-loader', 49 | options: { 50 | cacheDirectory: true, 51 | }, 52 | }, { 53 | loader: 'ts-loader', 54 | options: { 55 | appendTsSuffixTo: [/\.vue$/], 56 | happyPackMode: true, 57 | }, 58 | }], 59 | }, 60 | // js 61 | { 62 | test: /\.js$/, 63 | loader: 'babel-loader', 64 | include: [path.resolve(__dirname, '../src')], 65 | }, 66 | // img res 67 | { 68 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 69 | loader: 'url-loader', 70 | options: { 71 | limit: 10000, 72 | name: path.posix.join('static', 'img/[name].[hash:7].[ext]'), 73 | }, 74 | }, 75 | // media res 76 | { 77 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 78 | loader: 'url-loader', 79 | options: { 80 | limit: 10000, 81 | name: path.posix.join('static', 'media/[name].[hash:7].[ext]'), 82 | }, 83 | }, 84 | // font res 85 | { 86 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 87 | loader: 'url-loader', 88 | options: { 89 | limit: 10000, 90 | name: path.posix.join('static', 'fonts/[name].[hash:7].[ext]'), 91 | }, 92 | } 93 | ], 94 | }, 95 | resolve: { 96 | extensions: ['.js', '.vue', '.json'], 97 | alias: { 98 | 'vue$': 'vue/dist/vue.esm.js', 99 | '@': path.resolve(__dirname, '../src'), 100 | }, 101 | }, 102 | node: { 103 | // 避免 webpack 注入不必要的 setImmediate polyfill 因为 Vue 已经将其包含在内 104 | setImmediate: false, 105 | }, 106 | } 107 | -------------------------------------------------------------------------------- /build/webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const merge = require('webpack-merge') 3 | const baseWebpackConfig = require('./webpack.base.config') 4 | const HtmlWebpackPlugin = require('html-webpack-plugin') 5 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 6 | const portfinder = require('portfinder') 7 | const autoprefixer = require('autoprefixer') 8 | const {VueLoaderPlugin} = require('vue-loader') 9 | 10 | const devWebpackConfig = merge(baseWebpackConfig, { 11 | mode: 'development', 12 | devServer: { 13 | clientLogLevel: 'warning', 14 | historyApiFallback: { 15 | rewrites: [{from: /.*/, to: '/index.html'}], 16 | }, 17 | hot: true, 18 | contentBase: false, 19 | compress: true, 20 | host: process.env.HOST || 'localhost', 21 | port: +process.env.PORT || 8080, 22 | open: true, // 自动打开浏览器 23 | overlay: {warnings: false, errors: true}, // 展示全屏报错 24 | publicPath: '/', 25 | proxy: {}, 26 | quiet: true, // for FriendlyErrorsPlugin 27 | watchOptions: { 28 | poll: false, 29 | } 30 | }, 31 | module: { 32 | rules: [{ 33 | test: /\.(less|css)$/, 34 | use: [{ 35 | loader: 'vue-style-loader', 36 | }, { 37 | loader: 'css-loader', 38 | }, { 39 | loader: 'postcss-loader', 40 | options: { 41 | plugins: [ 42 | autoprefixer, 43 | ], 44 | } 45 | }, { 46 | loader: 'less-loader', 47 | }], 48 | }], 49 | }, 50 | devtool: 'cheap-module-eval-source-map', 51 | plugins: [ 52 | new webpack.DefinePlugin({ 53 | 'process.env': { 54 | NODE_ENV: '"development"', 55 | }, 56 | }), 57 | new VueLoaderPlugin(), 58 | new webpack.HotModuleReplacementPlugin(), 59 | new webpack.NamedModulesPlugin(), // 开启 HMR 的时候使用该插件会显示模块的相对路径 60 | new webpack.NoEmitOnErrorsPlugin(), 61 | new HtmlWebpackPlugin({ 62 | filename: 'index.html', 63 | template: 'index.html', 64 | inject: true, 65 | }), 66 | ], 67 | }) 68 | 69 | module.exports = new Promise((resolve, reject) => { 70 | portfinder.basePort = +process.env.PORT || 8080 71 | portfinder.getPort((err, port) => { 72 | if (err) { 73 | reject(err) 74 | } else { 75 | devWebpackConfig.devServer.port = port 76 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 77 | compilationSuccessInfo: { 78 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], 79 | }, 80 | onErrors: undefined, 81 | })) 82 | 83 | resolve(devWebpackConfig) 84 | } 85 | }) 86 | }) 87 | -------------------------------------------------------------------------------- /build/webpack.mp.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const eslintFriendlyFormatter = require('eslint-friendly-formatter') 4 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') 5 | const {VueLoaderPlugin} = require('vue-loader') 6 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin') 7 | const TerserPlugin = require('terser-webpack-plugin') 8 | const MpPlugin = require('mp-webpack-plugin') // 用于构建小程序代码的 webpack 插件 9 | const stylehacks = require('stylehacks') 10 | const autoprefixer = require('autoprefixer') 11 | const mpPluginConfig = require('./miniprogram.config.js') // 插件配置 12 | 13 | const isDevelop = process.env.NODE_ENV === 'development' 14 | const isOptimize = true // 是否压缩业务代码,开发者工具可能无法完美支持业务代码使用到的 es 特性,建议自己做代码压缩 15 | 16 | module.exports = { 17 | mode: 'production', 18 | entry: { 19 | // js 入口 20 | home: path.resolve(__dirname, '../src/mp/home/main.mp.js'), 21 | other: path.resolve(__dirname, '../src/mp/other/main.mp.js'), 22 | }, 23 | output: { 24 | path: path.resolve(__dirname, '../dist/mp/common'), // 放到小程序代码目录中的 common 目录下 25 | filename: '[name].js', // 必需字段,不能修改 26 | library: 'createApp', // 必需字段,不能修改 27 | libraryExport: 'default', // 必需字段,不能修改 28 | libraryTarget: 'window', // 必需字段,不能修改 29 | }, 30 | watch: isDevelop, 31 | target: 'web', // 必需字段,不能修改 32 | optimization: { 33 | runtimeChunk: false, // 必需字段,不能修改 34 | splitChunks: { // 代码分割配置,不建议修改 35 | chunks: 'all', 36 | minSize: 1000, 37 | maxSize: 0, 38 | minChunks: 1, 39 | maxAsyncRequests: 100, 40 | maxInitialRequests: 100, 41 | automaticNameDelimiter: '~', 42 | name: true, 43 | cacheGroups: { 44 | vendors: { 45 | test: /[\\/]node_modules[\\/]/, 46 | priority: -10 47 | }, 48 | default: { 49 | minChunks: 2, 50 | priority: -20, 51 | reuseExistingChunk: true 52 | } 53 | } 54 | }, 55 | minimizer: isOptimize ? [ 56 | // 压缩CSS 57 | new OptimizeCSSAssetsPlugin({ 58 | assetNameRegExp: /\.(css|wxss)$/g, 59 | cssProcessor: require('cssnano'), 60 | cssProcessorPluginOptions: { 61 | preset: ['default', { 62 | discardComments: { 63 | removeAll: true, 64 | }, 65 | minifySelectors: false, // 因为 wxss 编译器不支持 .some>:first-child 这样格式的代码,所以暂时禁掉这个 66 | }], 67 | }, 68 | canPrint: false 69 | }), 70 | // 压缩 js 71 | new TerserPlugin({ 72 | test: /\.js(\?.*)?$/i, 73 | parallel: true, 74 | }) 75 | ] : [], 76 | }, 77 | module: { 78 | rules: [ 79 | // html 80 | { 81 | test: /\.html$/, 82 | loader: 'raw-loader' 83 | }, 84 | // css 85 | { 86 | test: /\.(less|css)$/, 87 | use: [ 88 | { 89 | loader: MiniCssExtractPlugin.loader, 90 | options: { 91 | modules: true, 92 | }, 93 | }, 94 | { 95 | loader: 'css-loader' 96 | }, 97 | { 98 | loader: 'postcss-loader', 99 | options: { 100 | ident: 'postcss', 101 | plugins: () => { 102 | return [ 103 | autoprefixer, 104 | stylehacks(), // 剔除 ie hack 代码 105 | ] 106 | } 107 | } 108 | }, 109 | { 110 | loader: 'less-loader' 111 | } 112 | ], 113 | }, 114 | // eslint 115 | { 116 | test: /\.(js|vue)$/, 117 | loader: 'eslint-loader', 118 | enforce: 'pre', 119 | include: [path.resolve(__dirname, '../src')], 120 | options: { 121 | formatter: eslintFriendlyFormatter, 122 | emitWarning: true, 123 | }, 124 | }, 125 | // vue 126 | { 127 | test: /\.vue$/, 128 | use: [ 129 | 'thread-loader', 130 | { 131 | loader: 'vue-loader', 132 | options: { 133 | compilerOptions: { 134 | preserveWhitespace: false 135 | } 136 | } 137 | }, 138 | 'vue-improve-loader', 139 | ] 140 | }, 141 | // ts 142 | { 143 | test: /\.tsx?$/, 144 | exclude: /node_modules/, 145 | use: [{ 146 | loader: 'thread-loader', 147 | }, { 148 | loader: 'babel-loader', 149 | options: { 150 | cacheDirectory: true, 151 | }, 152 | }, { 153 | loader: 'ts-loader', 154 | options: { 155 | appendTsSuffixTo: [/\.vue$/], 156 | happyPackMode: true, 157 | }, 158 | }], 159 | }, 160 | // js 161 | { 162 | test: /\.js$/, 163 | use: [ 164 | 'thread-loader', 165 | { 166 | loader: 'babel-loader', 167 | options: { 168 | cacheDirectory: true, 169 | } 170 | } 171 | ], 172 | exclude: /node_modules/ 173 | }, 174 | // res 175 | { 176 | test: /\.(png|jpg|jpeg|gif|svg|eot|woff|woff2|ttf)$/, 177 | use: [{ 178 | loader: 'url-loader', 179 | options: { 180 | limit: 1024, 181 | name: '[name]_[hash:hex:6].[ext]', 182 | publicPath: 'https://test.miniprogram.com/res', // 对于资源文件直接使用线上的 cdn 地址 183 | emitFile: false, 184 | } 185 | }], 186 | }, 187 | ] 188 | }, 189 | resolve: { 190 | extensions: ['.js', '.vue', '.json'], 191 | alias: { 192 | 'vue$': 'vue/dist/vue.esm.js', 193 | '@': path.resolve(__dirname, '../src'), 194 | }, 195 | }, 196 | plugins: [ 197 | new webpack.DefinePlugin({ 198 | 'process.env.isMiniprogram': process.env.isMiniprogram, // 注入环境变量,用于业务代码判断 199 | }), 200 | new MiniCssExtractPlugin({ 201 | filename: '[name].wxss', 202 | }), 203 | new VueLoaderPlugin(), 204 | new MpPlugin(mpPluginConfig), 205 | ], 206 | } 207 | -------------------------------------------------------------------------------- /build/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const merge = require('webpack-merge') 4 | const baseWebpackConfig = require('./webpack.base.config') 5 | const HtmlWebpackPlugin = require('html-webpack-plugin') 6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') 7 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin') 8 | const TerserPlugin = require('terser-webpack-plugin') 9 | const autoprefixer = require('autoprefixer') 10 | const {VueLoaderPlugin} = require('vue-loader') 11 | 12 | const webpackConfig = merge(baseWebpackConfig, { 13 | mode: 'production', 14 | output: { 15 | path: path.resolve(__dirname, '../dist/web'), 16 | filename: path.posix.join('static', 'js/[name].[chunkhash].js'), 17 | chunkFilename: path.posix.join('static', 'js/[id].[chunkhash].js') 18 | }, 19 | optimization: { 20 | splitChunks: { // 代码分割配置 21 | chunks: 'async', 22 | minSize: 30000, 23 | maxSize: 0, 24 | minChunks: 1, 25 | maxAsyncRequests: 5, 26 | maxInitialRequests: 3, 27 | automaticNameDelimiter: '~', 28 | name: true, 29 | cacheGroups: { 30 | vendors: { 31 | test: /[\\/]node_modules[\\/]/, 32 | priority: -10 33 | }, 34 | default: { 35 | minChunks: 2, 36 | priority: -20, 37 | reuseExistingChunk: true 38 | } 39 | } 40 | }, 41 | minimizer: [ 42 | // 压缩CSS 43 | new OptimizeCSSAssetsPlugin({ 44 | assetNameRegExp: /\.css$/g, 45 | cssProcessor: require('cssnano'), 46 | cssProcessorPluginOptions: { 47 | preset: ['default', { 48 | discardComments: { 49 | removeAll: true, 50 | }, 51 | }], 52 | }, 53 | canPrint: false 54 | }), 55 | // 压缩 js 56 | new TerserPlugin({ 57 | test: /\.js(\?.*)?$/i, 58 | parallel: true, 59 | }), 60 | ], 61 | }, 62 | devtool: false, 63 | module: { 64 | rules: [{ 65 | test: /\.(less|css)$/, 66 | use: [{ 67 | loader: MiniCssExtractPlugin.loader, 68 | }, { 69 | loader: 'css-loader', 70 | }, { 71 | loader: 'postcss-loader', 72 | options: { 73 | plugins: [ 74 | autoprefixer, 75 | ], 76 | } 77 | }, { 78 | loader: 'less-loader', 79 | }], 80 | }], 81 | }, 82 | plugins: [ 83 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 84 | new webpack.DefinePlugin({ 85 | 'process.env': { 86 | NODE_ENV: '"production"', 87 | }, 88 | }), 89 | new VueLoaderPlugin(), 90 | // 分离 css 文件 91 | new MiniCssExtractPlugin({ 92 | filename: path.posix.join('static', 'css/[name].[hash].css'), 93 | }), 94 | new HtmlWebpackPlugin({ 95 | filename: path.resolve(__dirname, '../dist/web/index.html'), 96 | template: 'index.html', 97 | inject: true, 98 | minify: { 99 | removeComments: true, 100 | collapseWhitespace: true, 101 | removeAttributeQuotes: true 102 | // 更多配置:https://github.com/kangax/html-minifier#options-quick-reference 103 | }, 104 | chunksSortMode: 'dependency' 105 | }), 106 | // 当 vendor 模块没有改变时,保证模块 id 不变 107 | new webpack.HashedModuleIdsPlugin(), 108 | ], 109 | }) 110 | 111 | module.exports = webpackConfig 112 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |{{headerTips}} {{input}}
4 |这段话不会在小程序里显示
13 |在构建的时候就会被 vue-improve-loader 给干掉了
14 |这段话也不会在小程序里显示
18 |在构建的时候就会被 reduce-loader 给干掉了
19 |这段话也不会在小程序里显示
23 |在渲染时会被样式隐藏
24 |