# webpack-miniprogram-plugin **Repository Path**: janpoem/webpack-miniprogram-plugin ## Basic Information - **Project Name**: webpack-miniprogram-plugin - **Description**: webpack微信小程序开发/打包插件,提供多环境的微信小程序开发/打包环境,实现开发/测试/产品模式的分离,支持不同开发用户自定义的小程序配置文件,通过 webpack.DefinePlugin 可以轻松解决不同环境下的配置分离。 - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 29 - **Forks**: 6 - **Created**: 2019-05-16 - **Last Updated**: 2022-09-02 ## Categories & Tags **Categories**: weixin-lapp **Tags**: None ## README # webpack-miniprogram-plugin [![Npm version](https://img.shields.io/npm/v/webpack-miniprogram-plugin.svg)](https://www.npmjs.com/package/webpack-miniprogram-plugin) ## 介绍 webpack微信小程序开发/打包插件,提供多环境的微信小程序开发/打包环境,实现开发/测试/产品模式的分离,支持不同开发用户自定义的小程序配置文件,通过 webpack.DefinePlugin 可以轻松解决不同环境下的配置分离。 主要特性: 1. 该插件理论上兼容所有前端已知开发环境,开发者可配置成自己需要的开发环境,如:typescript,各种 Babel 的转译插件,SASS/LESS/Stylus,PostCSS等。 2. 支持小程序所有的模式,wxs、template、component 3. 支持分离开发/测试/产品环境,借用 webpack.DefinePlugin ,可以轻松实现多环境(分离不同的appid,接口base url)打包,再也不用担心上传错线上版本了。 4. 不再局限于原有的 app.json 和 project.config.json ,真正做到每个开发者可以拥有自己的配置,能迅速提升你小程序项目的代码格局。 ## 更新说明 **1.0.3** * 增加对已经从 json 中移除的 page 和 component 的 chunk 移除(包括对应的 assets)。 * 优化 seekApp() 的入口。 * 去掉默认的 sitemap.json ,转为根据 app.json 探测。 **1.0.4** * 插件 options 增加一个 `mockMain` 参数,创建一个模拟入口,来替代 `main` ,用于兼容一个小程序项目多个开发者参与,需要有不同的配置入口。对应的 json-loader 的写法,参考如下: ```javascript { test: /\.(json)$/, type: 'javascript/auto', use: { loader: "file-loader", options: { name: (filename) => { const path = replaceDS(pathUtil.relative(srcPath, filename)); const reg = /app.(([a-z0-9-_]+).json)$/; // 假定我的项目中自定义的 app.json 文件为:app.custom.json if (path.match(reg)) { return path.replace(reg, 'app.json'); // 还原成 app.json 输出 } return path; }, }, } } ``` **1.0.5** * 修正 tabBar 解析的bug ## 安装说明 ```console npm install webpack-miniprogram-plugin // or yarn add webpack-miniprogram-plugin ``` ## 使用示例 具体参考 `test/webpack.config.js` 文件。 ```javascript module.exports = { output: { libraryTarget: 'var', // 必须 }, target: 'node', // 必须 plugins: [ new MiniProgramPlugin(src, dist, options), ] }; ``` options 的参考: ```javascript const options = { main: 'app.json', mockMain: 'app.my.json', // 创建一个模拟入口 debug: false, assets: 'assets', assetsChunkName: '__assets_chunk_name__', bootstrapModuleName: 'bootstrap.js', // 公共附件后缀名,以 object 结构,如果要去掉某类文件,value 取 false exts: { json: true, wxml: true, wxss: false, }, // 脚本后缀名 scriptExts: {js: true}, // 需要检查 io stat 的文件后缀,wxss 不是必选项,可能存在 page 或者 component 没有 wxss 文件 checkStatExts: {wxss: true}, // app.js - app.json 的特定附加文件。 app: { exts: {wxml: false}, // 附加文件 files: [ // 不附加文件的话,files: false 'sitemap.json', 'project.config.json', ], }, // page 范围内的设定 page: { // 使用公共的后缀文件名 // exts: {wxml: true}, files: [], }, // component 范围内的设定 component: { // exts: {wxml: true}, files: [], }, // 自定义路径匹配指定附加文件 custom: { // 指定 pages/index/index 的附加设定 'pages/index/index': { files: ['ok.json'], }, }, } ``` ## 引入依赖的路径写法 开发中引入 js 的路径,请严格遵照 npm 的标准,当前目录下的文件,应该是 `require('./mobx')` 或者 `require('./any-module')` ,`require('loadsh')` 表示引入 node_modules 下的 module。否则会导致 webpack 编译处理 js 的依赖关系时报错。 component 支持绝对路径和相对路径的两种写法:`../../components/hello/world` 或 `/components/hello/world` 。 已经支持检索 app.json 中的 `pages`, `subPackages`, `tabBar` ,以及各个 json 中定义的 `useComponents` 字段。 ## 样式文件 ### 通过JS引入的模式(推荐) 样式文件,推荐在对应的 js 文件中引入(require 或 import),这样的好处是,可以使用 `mini-css-extract-plugin` 或 `extract-css-chunks-webpack-plugin` ,来打包分离成对应的 wxss 文件,最终输出的效果更好。 loaders 可以参照如下的配置: ```javascript module.exports = { module: { rules: [ { test: /\.styl$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader'], }, { test: /\.(css|wxss)$/, use: [MiniCssExtractPlugin.loader, 'css-loader'], }, ] } } ``` ### 复制wxss模式 如果你希望插件对待 wxss 文件时,作为附加文件的模式处理的话,也是可以的,需要做如下的设置: ```javascript const path = require('path'); module.exports = { module: { rules: [ { test: /\.(wxss)$/, use: { loader: 'file-loader', options: { name: (filename) => replaceDS(path.relative(srcPath, filename)), // 文件名路径名转换 }, }, }, ] }, plugins: [ new MiniProgramPlugin(src, dist, { exts: { wxss: true, // 开启 wxss 作为附件打包 } }), ] }; ``` ### 附上实际项目 webpack 配置 本项目的一个出发点,就是为了能够彻底的活用 webpack 自身强大的可定制化功能,不考虑做脚手架,将配置内定,所以以下配置内容可能略微硬核。 ```javascript const src = 'src'; const srcPath = pathUtil.resolve(process.cwd(), src); // 转路径的分隔符号,主要针对windows const replaceDS = (path) => path.replace(/[\\/]+/g, '/'); const options = { // 指定以一个用户自己的 app.user.json 来替代 app.json,也是为了隔离不同用户版本、不同打包环境 // 这样能彻底的使得参与项目的开发者,只需要关注自己那部分配置即可 mockMain: 'app.user.json', app: { files: [ // 指定App的附加文件 // 使用自定义的 project.config.json 来提供默认项目配置 ,确保开发环境和发布环境分离, // 这样可以做到每个开发者使用自己的配置,或者是同一个项目可以打包成多个项目 'project.config.dev.user.json', // wxs 文件支持 'wxs/utils.wxs', ] } }; // webpack 的配置 const webpackConfig = { mode: env === 'development' ? 'development' : 'production', entry: { app: [`./${src}/app.js`], }, output: { filename: '[name].js', libraryTarget: 'var', path: pathUtil.resolve(__dirname, dist), }, target: 'node', module: { rules: [ // 传统 js 的 babel 转译 { test: /\.(js)$/, use: [ { loader: 'babel-loader', options: { presets: ['@babel/env'], plugins: [ ['@babel/plugin-proposal-decorators', { "legacy": true, }], ['@babel/plugin-proposal-class-properties', { "loose": true, }], '@babel/plugin-transform-modules-commonjs', '@babel/plugin-transform-block-scoping', '@babel/plugin-transform-computed-properties', '@babel/plugin-proposal-object-rest-spread', ], }, }, ], }, // 图片处理 { test: /\.(png|jpg)$/, use: { loader: "file-loader", options: { name: (filename) => { return replaceDS(pathUtil.relative(srcPath, filename)); }, }, }, }, // json 文件处理 { test: /\.(json)$/, type: 'javascript/auto', // 新版webpack对json处理方式不同了,需要加这一句 use: { loader: "file-loader", options: { name: (filename) => { const path = replaceDS(pathUtil.relative(srcPath, filename)); // 以下就是将 mock 的 json 文件,替代为实际有效的 app.json 和 project.config.json 来输出 const appReg = /app.(([a-z0-9-_]+).json)$/; // 假定我的项目中自定义的 app.json 文件为:app.custom.json const projectReg = /project.config.([a-z0-9-_]+)(.([a-z0-9-_]+))?.json$/; if (path.match(appReg)) { return path.replace(appReg, 'app.json'); // 还原成 app.json 输出 } if (path.match(projectReg)) { return path.replace(projectReg, 'project.config.json'); } return path; }, }, }, }, // wxml { test: /\.(wxml)$/, use: { loader: "file-loader", options: { name: (filename) => { return replaceDS(pathUtil.relative(srcPath, filename)); }, }, }, }, // wxs 文件 也用 babel 来处理 { test: /\.(wxs)$/, use: [ { loader: "file-loader", options: { name: (filename) => { return replaceDS(pathUtil.relative(srcPath, filename)); }, }, }, { loader: 'babel-loader', options: { presets: ['@babel/env'], plugins: [ ['@babel/plugin-proposal-decorators', { "legacy": true, }], ['@babel/plugin-proposal-class-properties', { "loose": true, }], '@babel/plugin-transform-modules-commonjs', '@babel/plugin-transform-block-scoping', '@babel/plugin-transform-computed-properties', '@babel/plugin-proposal-object-rest-spread', ], }, }, ], }, // 这个项目使用了 stylus { test: /\.styl$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader'], }, // 一般的 css { test: /\.(css|wxss)$/, use: [MiniCssExtractPlugin.loader, 'css-loader'], }, ], }, plugins: [ // 这里主要是因应不同 env 混入不同的 JS 常量,比如 API 地址,请参考 webpack/DefinePlugin webpackPredef(env, predef.webpack, env.custom), // 这里主要是因应不同的 env 的 stylus 全局常量,比如 CDN base url,请参考 stylusLoader.OptionsPlugin。 new stylusLoader.OptionsPlugin({ default: { use: [stylusPredef(env, predef.stylus)], }, }), new MiniProgramPlugin(src, dist, options), new MiniCssExtractPlugin( { filename: "[name].wxss", }, ), ], devtool: 'inline', optimization: { splitChunks: { cacheGroups: { // src/utils, src/lib, src/model, src/store, src/actions, node_modules 路径下的代码,合并打包成一个独立的 lib.js 文件 modules: { test: /([\\/](utils|lib|model|store|actions|node_modules)[\\/])/, name: 'lib', minSize: 0, minChunks: 1, chunks: 'all', }, }, }, }, }; ```