前言
最近项目所需,所以开始学习并且使用 APICloud 此款 hybrid APP 开发框架。粗略的看了下文档和部分 Demo 后,已经对 APICloud 开发有一定基础的了解。在这种过程令我有一点疑惑,APICloud 的开发流程和普通的 Web APP 开发其实是很相似的,但是却没有对目前主流的构建工具有先关的教程。我发现虽然官方提供了一个 apicloud-polyfill 的功能,但是只是为了解决在项目中使用 ES6 的问题,而且整个 demo 的开发体验并不好,每次修改代码需要不停的构建在增量更新。随着项目的复杂起来,以及对一些前端新特性的依赖,所以我打算自己动手弄一个适合 APICloud 使用的 Webpack 模板。
项目结构
APICloud 的开发模式其实就是以前的使用 jQuery 的 MPA 开发一样,而且官方不推荐使用 SPA 的开发模式。
|- dist|- lanuch|- src |- pages |- Foo |- index.js |- index.html |- image |- css |- scripts |- index.js |- index.html|- package.json|- config.xml|- webpack.config.json|- .babelrc|- .gitignore|- .syncignore|- index.html
上面是我个人对 APICloud 项目的文件夹分类。所有的源码都存放在 src 文件夹内,Webpack 打包的主要目录也是 src。
这里规定了每一个单独的 HTML 页面都是需要一个 JavaScript 的入口文件,这也是为了使用 Webpack 进行多页面打包的基础。
Webapck 基础配置文件
在设定好目录结构之后,我们需要开始编写 Webpack 的 config 文件,配置相对来首都比较简单,所以我们就写在一个文件内既可。
webpack.config.js
const path = require('path')const webpack = require('webpack')const HtmlWebpackPlugin = require('html-webpack-plugin')const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin')const glob = require('glob')const paths = {}const configs = []const setPath = (item, type) => { const dirname = path.dirname(item) if (paths[dirname]) { paths[dirname][type] = item } else { paths[dirname] = { [type]: item } }}glob.sync('./src/**/*.js', { ignore: './src/script/*.js' }).forEach(item => setPath(item, 'script'))glob.sync('./src/**/*.html').forEach(item => setPath(item, 'html'))Object.keys(paths).forEach(key => { const distName = key.replace('src', 'dist') configs.push({ entry: paths[key].script, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, distName) }, devtool: process.env.NODE_ENV === 'production' ? 'inline-source-map' : '#source-map', devServer: { host: '0.0.0.0', port: 8080, historyApiFallback: false, noInfo: true }, resolve: { extensions: ['.js', '.vue'], alias: { '@': path.resolve(__dirname, 'src'), 'vue$': 'vue/dist/vue.esm.js' } }, module: { rules: [ { test: /\.js$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader' }, { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(png|svg|jpg|gif)$/, use: [ 'file-loader' ] }, { test: /\.(woff|woff2|eot|ttf|otf)$/, use: [ 'file-loader' ] } ] }, plugins: [].concat( [ new HtmlWebpackPlugin({ inlineSource: '.(js|css)$', template: paths[key].html }) ], process.env.NODE_ENV === 'production' ? [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), new webpack.optimize.UglifyJsPlugin({ sourceMap: true, compress: { warnings: false } }), new webpack.LoaderOptionsPlugin({ minimize: true }), new HtmlWebpackInlineSourcePlugin(), ] : [] ) })})module.exports = configs
package.json
{ "name": "webpack-demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "cross-env NODE_ENV=production webpack --progress ", "dev": "cross-env NODE_ENV=development webpack-dev-server --open" }, "author": "", "license": "ISC", "devDependencies": { "babel-core": "^6.25.0", "babel-loader": "^7.1.1", "babel-preset-env": "^1.6.0", "cross-env": "^5.0.5", "css-loader": "^0.28.4", "file-loader": "^0.11.2", "glob": "^7.1.2", "html-webpack-inline-source-plugin": "0.0.9", "html-webpack-plugin": "^2.30.1", "style-loader": "^0.18.2", "webpack": "^3.5.4", "webpack-dev-server": "^2.7.1" }, "dependencies": { "vue": "^2.4.2" }}
在 Webpack 中我们导出的是一个 config 数组,通过扫描 src 文件下的 JavaScript 和 HTML 文件,获取它们的 path 信息,为每一个 JavaScript 进行打包。此外我们可能还需要忽略一些 JavaScript 文件。
在生产环境的构建下,我配置了将 css 和 JavaScript 都插入了 html 文件中,这又是官方的一种提倡做法。
估计上面的配置好后,设置两个 npm script 命令,方便开发使用:
-
npm run dev
:启动本地开发服务器; -
npm run build
:编译项目,输出到 dist 目录下。
修改入口地址
在 APICloud 项目里,我们在根目录有一个 index.html 文件,这是一个入口文件,我们可以通过修改 config.xml 来修改入口文件。一般来说都是通过 openFrame 或者 openWin 来嵌入或者打开一个页面,在我们的本地开发环境下,我们通过 Webpack 启动了一个本地服务器进行调试,所以我们也需要将地址从目录的相对地址改为一段 url。例如:
如果需要编译项目的话,入口文件也需要修改成相对路径。这是一个麻烦的点,目前还没什么好办法解决。
集成 ESlint
目标,在开发和编译过程中 Webpack 能够使用 eslint 检查代码,出现错误不通过,使用 aribnb 的 JavaScript 风格编程。
webpack.config.json
...configs.push({ ... module: { rules: [ { enforce: "pre", test: /\.js$/, exclude: /(node_modules|bower_components)/, loader: "eslint-loader", }, ... ] }})...
package.json
{ ... devDependencies: { ... "eslint": "^4.4.1", "eslint-config-airbnb-base": "^11.3.1", "eslint-loader": "^1.9.0", "eslint-plugin-html": "^3.2.0", "eslint-plugin-import": "^2.7.0", ... } ...}
.eslintrc
{ "extends": "airbnb-base", "plugins": [ "html" ]}
.eslintignore
node_modulesdist*.css
结语
这次对 APICloud 集成 Webpack 尝试,结果还算可。但是个人对 APICloud 的开发还是非常的不满意的,对于 React Native 来说:没有热更新、在 APP loader 下调试不能使用 Chrome developer tool等。看网上对这个框架的评价,也是处于一个较低的水平。只能通过这次项目的开发再深入了解的它们的利弊了。
项目地址: