-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Labels
Description
mobile-intl 框架起源
基于多页框架项目 vue-multiple-pages 优化
基础 webpack 配置
配置文件
-
通常情况,根目录下面的
webpack.config.js文件作为默认配置文件 -
自定义配置文件,使用
--config指定配置文件
package.json
"scripts": {
"build": "webpack --config prod.config.js"
}常用配置项:
const path = require("path");
module.exports = {
// 选择模式,webpack 可以根据选择启用内置优化
mode: "production", // "production" | "development" | "none"
// webpack 打包入口,单页应用配字符串,多页应用配对象或数组
entry: "./app/entry", // string | object | array
entry: {
a: "./app/entry-a",
b: ["./app/entry-b1", "./app/entry-b2"]
},
// 打包文件输出配置
output: {
// 所有文件的输出目录,必须是个绝对路径
path: path.resolve(__dirname, "dist"), // string
filename: "bundle.js", // string
filename: "[name].js", // 多入口
// 分块(chunks)入口的名字
publicPath: "/mobile-intl/" // string
// 输出路径相对于 HTML 页面的 url
},
// 处理各种模块的 Loader
module: {
rules: [{
test: /\.jsx?$/,
include: [path.resolve(__dirname, "app")],
exclude: [path.resolve(__dirname, "app/demo-files")],
loader: "babel-loader", // Rule.use: [ { loader } ] 的简写,loader 名称
options: {
// Rule.use: [ { options } ] 的简写,loader 配置
presets: ["es2015"]
}
},
{
test: /\.html$/,
use: [
// 配置多个 loader
"htmllint-loader",
{
loader: "html-loader",
options: {
/* ... */
}
}
]
}
]
},
// 模块解析配置
resolve: {
// 模块搜索目录
modules: ["node_modules", path.resolve(__dirname, "app")],
// 文件扩展名
extensions: [".js", ".json", ".jsx", ".css"],
// 别名
alias: {
vue: "vue/dist/vue.js",
vuex: "vuex/dist/vuex.js",
"@": path.resolve("src")
}
},
// 性能报告
performance: {
hints: "warning", // enum
},
// source map 如何生成,调试便利和编译速度如何权衡
devtool: "source-map",
// 配置 webpack-serve
serve: {
port: 1337,
content: "./dist"
},
// 精确控制命令行输出日志
stats: "errors-only",
// webpack-dev-server 配置
devServer: {
proxy: {
// 后端接口代理,可用于 mock 数据
"/api": "http://localhost:3000"
},
contentBase: path.join(__dirname, "public"), // boolean | string | array, 静态文件目录
compress: true, // 启用 gzip 压缩
hot: true, // 模块热替换
noInfo: true, // 热更新时仅输出错误和警告日志
stats: { // 命令行日志信息
},
},
// 插件配置
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
]
};全部配置见官方文档
快速生成自定义配置文件,可以用官方推荐工具
打包输出目录优化
精简多余的目录
// CSS 目录
const extractCSS = new ExtractTextPlugin({
// filename: 'assets/css/[name].css',
filename: (getPath) => {
return getPath('assets/css/[name].css').replace('views/', '');
}
})
// HTML 目录
filename = filename.replace('views/', '')
const htmlConf = {
filename: filename,
template: path.replace(/.js/g, '.html'),
inject: 'body',
hash: true,
chunks: ['commons', chunk]
}
// JS 目录
const _chunk = path.split('./src/pages/')[1].split('/app.js')[0]
const chunk = _chunk.replace('views/', '')项目启动优化
From
npm start
To
# 自定义调试项目,customer 为项目的目录名字
npm start -- --index=customer
实现思路
想办法把 openPage 字段变成动态值
devServer: {
open: true,
openPage: 'mobile-intl/index.html',
}
如何实现
- 传入参数
npm start -- --index=customer// package.json
scripts: {
"start": "node ./tools/runDev.js",
}- Node.js 截取参数
let params = process.argv
- 补全路径
let indexPage = params.find(function(it) {
return it.indexOf('--index=') > -1 // 找到起始页标识
})
...
let indexPath = indexPage.split('--index=')[1]
indexPage = 'mobile-intl/'+ indexPath +'/index.html'- 设置 webpack 参数
let shell = require('shelljs');
let script = 'webpack-dev-server --open-page='+ indexPage +' --inline --hot --config build/webpack.dev.conf.js'
shell.exec(script)添加路径别名
alias: {
'@': resolve('src'),
'pages': resolve('src/pages'),
'components': resolve('src/components'),
'services': resolve('src/services')
}import { gtagPV } from '@/utils/gtag';不同环境自动适配域名
原则上不允许硬编码域名,直接写路径 path,或者引入以下 JS 统一处理
// 前端URL,直接写路径
window.location.href = '/helloworld/help/index.html'
// 后端接口
import conf from 'services/config'
console.log(conf.host)webpack 在打包时会自动对域名相关信息进行替换。
如何实现
- 针对不同环境,使用不同的配置文件,比如:config.js,config-qa.js
保证所有配置文件导出的参数名保持一致
// dev 测试环境配置
let baseUrl = 'dev.xxx.com' // 服务端接口环境
let host = '//'+ window.location.hostname // 前端网页域名
export default {
baseUrl,
host
}
- webpack 通过
NormalModuleReplacementPlugin插件完成替换
const prodWebpackConfig = merge(webpackConfig, {
plugins: [
new webpack.NormalModuleReplacementPlugin(
/services\/config\.js/, // services 目录默认配置文件
'./config-qa.js' // 替换配置文件
)
]
})接口请求完善
- 编写通用拦截器
// 请求拦截器
axios.interceptors.request.use(function (config) {
// 自动添加 token 之类的通用参数
return config;
}, function (error) {
return Promise.reject(error);
});
// 响应拦截器
axios.interceptors.response.use(function (response) {
// 处理一些通用响应,比如 200,401之类
return response;
}, function (error) {
return Promise.reject(error);
});使用时引入一次拦截器,发起请求同 axios API
import axios from 'services/axios'
axios.get('/api?param=value')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});- 请求方法封装
import { postFromData } from 'services/axios'
// postFromData:post 请求以 form 表单形式发送数据,默认为 JSON
postFromData.then((response) => {
console.log(response);
}).catch((error) => {
console.log(error);
})服务器部署优化
优化效果
# 单独打包
npm run buildDev // 打 dev 环境包
npm run buildQa // 打 QA 环境包
npm run buildPre // 打仿真环境包
npm run buildOnline // 打线上环境包
# 单独部署
npm run dev // 部署 dev 测试环境
npm run qa // 部署 QA 测试环境
npm run pre // 部署仿真测试环境
npm run online // 部署线上环境
# 打包 + 部署快捷方式
# 第一个参数为打包所用的 server 接口环境,第二个参数为服务器部署环境
# 两个参数的可选值均为:dev || qa || pre || online
# 调用方式一
npm run deploy -- --buildEnv=dev --deployEnv=qa
# 调用方式二
npm run deploy -- dev qa如何实现
- 创建通用的 webpack 配置:
webpack.cust.conf.js,处理各个环境的打包逻辑
// exports function 能接收参数
module.exports = function(env, argv){
// 根据 npm run script 传入的参数判断环境
let apiEnv = env.serverApi || 'dev'
if (apiEnv === 'dev'){
// 做点啥
}
}- npm script 传入 webpack 参数:
serverApi,实现环境自定义
"scripts": {
"buildDev": "webpack --env.serverApi dev --mode production --progress --color --config build/webpack.cust.conf.js",
"buildQa": "webpack --env.serverApi qa --mode production --progress --color --config build/webpack.cust.conf.js",
}- npm script 传入 node 参数:
env,实现部署服务器自定义
"scripts": {
"dev": "node deploy.js --env=dev --color=always",
"qa": "node deploy.js --env=qa --color=always",
}// deploy.js 为部署脚本
let envParam = process.argv[2].slice(6) // 裁掉 --env= 获取环境参数
let deployEnv = envParam || 'dev' // 服务器环境初始化项目脚手架
初始化项目结构
- 单页项目模板
/src/pages/singlePage - 多页项目模板
/src/pages/multiPage
根据提问完成项目初始化
npm run initApp如何实现
并没用Yeoman
关键工具
- 命令行交互:inquirer
- 下载 git 库:download-git-repo
提问交互
const askQuestion = async () => {
// 模板类型
let { templateType } = await inquirer.prompt([
{
type: 'list',
name: 'templateType',
message: 'Which template do you want?',
choices: [
{
name: 'SPA (Single page)',
value: 'SPA'
}
]
}
])
// 项目名称
let { projectName } = await inquirer.prompt([
{
name: 'projectName',
message: 'What\'s the project name',
}
])
}
askQuestion().catch((err) => {
console.log('init project err: ', err)
})拷贝工程模板
let shell = require('shelljs');
let sourcePath = '../src/pages/singlePage'
shell.cp('-R', sourcePath, '../src/pages/newProject');打包时排除模板目录
glob.sync('./src/pages/**/app.js', {
// 忽略项目模板目录
ignore: ['./src/pages/singlePage/**', './src/pages/multiPage/**']
}).forEach(path => {
// do something
})独立脚手架模板
可以利用 download-git-repo,把项目模板从 github 下载下来
命令行日志美化
关键工具
遇到的坑
使用 shelljs 库执行的时候,命令行的样式失效,issue 在此
解决办法
强制启用命令行样式
- webpack 加
--color
webpack --env.serverApi dev --mode production --progress --color --config build/webpack.cust.conf.js
- Node 加
--color=always
cd ./tools && node deploy.js --env=dev --color=always
自定义日志输出样式
参考了 signale 的样式,直接用它也没问题
const chalk = require('chalk');
// log with chalk
const chalkLog = function(options){
options = options || {
color: 'red', // chalk color
label: 'my-project',
badge: '🎉',
tag: 'tag',
msg: 'some log msg',
}
let logLabel = options.label || 'my-project'
let logColor = options.color || 'black'
const logTxt = chalk.gray('['+ logLabel +'] > ') + chalk[logColor](''+ options.badge +' ') + chalk.underline(chalk[logColor](options.tag)) +' '+ options.msg
console.log(logTxt)
}Reactions are currently unavailable
