|
@@ -0,0 +1,218 @@
|
|
|
+# Webpack
|
|
|
+
|
|
|
+遵循`MVP`原则, 即`最简化可实行产品`原则, 示例:
|
|
|
+
|
|
|
+## 既有项目引入新的组件/库
|
|
|
+
|
|
|
+假设现有项目用到了 `react`, `react-router` , `antd` 等库, 并且 `controller`, `router`, `model`, `view` 已基本成型.
|
|
|
+
|
|
|
+此时如果要引入 `mobx`, 最佳实践步骤为:
|
|
|
+
|
|
|
+1. 新建一个空项目, 将既有库 `react`, `antd` 等安装, 配置一个最简单的 `hello world` 路由
|
|
|
+2. 安装 `mobx`, 引入并测试通过
|
|
|
+3. 再在原有项目上进行功能扩充
|
|
|
+
|
|
|
+## 既有项目打包优化
|
|
|
+
|
|
|
+假设现有项目用到了 `react`, `react-router` , `antd`, `mobx` 等库, 并且 `controller`, `router`, `model`, `view` 已基本成型. webpack打包过大, 应用性能较差.
|
|
|
+
|
|
|
+最佳实践步骤:
|
|
|
+
|
|
|
+1. 新建一个空项目, 新建一个空的webpack配置
|
|
|
+2. 安装 `react` (或 `antd`, 或 `mobx`等) 写一个简单示例引入项目
|
|
|
+3. 针对单一库进行 `webpack` 打包优化, 一般情况下, 除了 loader rules / vendor 需要每个库单独优化, 其他配置都能保证通用
|
|
|
+4. 一项优化完成后重复2,3步骤, 直到所有库优化完成
|
|
|
+5. 对原有项目的 webpack 配置进行替换, 不动项目源码
|
|
|
+6. 进一步优化, 比如 `react-router-loader` 之类的引入, 开始针对项目源码进行优化
|
|
|
+
|
|
|
+## 示例: React/Antd 项目初始化
|
|
|
+
|
|
|
+### 1. 配置 eslint
|
|
|
+
|
|
|
+- 创建: `.eslintrc` 和 `.eslintignore`
|
|
|
+- 安装: `yarn add --dev eslint eslint-config-dwing eslint-config-airbnb eslint-plugin-react eslint-plugin-jsx-a11y babel-eslint`
|
|
|
+
|
|
|
+```js
|
|
|
+// .eslintrc.js
|
|
|
+module.exports = {
|
|
|
+ extends: [
|
|
|
+ 'eslint-config-dwing',
|
|
|
+ 'eslint-config-airbnb-base/rules/strict',
|
|
|
+ 'eslint-config-airbnb/rules/react'
|
|
|
+ ].map(require.resolve),
|
|
|
+ plugins: [
|
|
|
+ 'react'
|
|
|
+ ],
|
|
|
+ parser: 'babel-eslint',
|
|
|
+ env: {
|
|
|
+ browser: true
|
|
|
+ }
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 配置 babel
|
|
|
+
|
|
|
+- 创建: `.babelrc`
|
|
|
+- 安装: `yarn add --dev babel-preset-env babel-preset-react babel-plugin-transform-runtime babel-plugin-transform-decorators-legacy babel-plugin-import babel-plugin-transform-class-properties babel-plugin-transform-object-rest-spread babel-runtime babel-polyfill babel-core`
|
|
|
+
|
|
|
+```js
|
|
|
+// .babelrc
|
|
|
+{
|
|
|
+ "presets": [
|
|
|
+ ["env", {
|
|
|
+ "targets": {
|
|
|
+ "browsers": ["last 2 versions"]
|
|
|
+ }
|
|
|
+ }],
|
|
|
+ "react"
|
|
|
+ ],
|
|
|
+ "plugins": [
|
|
|
+ ["transform-runtime", {
|
|
|
+ "helpers": false,
|
|
|
+ "polyfill": false,
|
|
|
+ "regenerator": true,
|
|
|
+ "moduleName": "babel-runtime"
|
|
|
+ }],
|
|
|
+ "transform-decorators-legacy",
|
|
|
+ ["import", { "libraryName": "antd", "style": true }],
|
|
|
+ "transform-class-properties",
|
|
|
+ "transform-object-rest-spread"
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 安装 react/antd 等
|
|
|
+
|
|
|
+- 安装: `yarn add react react-dom react-router antd mobx`
|
|
|
+- webpack相关: `yarn add --dev babel-loader less less-loader css-loader postcss-loader autoprefixer`
|
|
|
+
|
|
|
+### 4. 配置 webpack
|
|
|
+
|
|
|
+- 创建: `webpack.config.js` (用作产品) `webpack.config.dev.js` (用作开发)
|
|
|
+- 安装: `yarn add --dev webpack html-webpack-plugin extract-text-webpack-plugin`
|
|
|
+
|
|
|
+该示例项目源码: <https://github.com/AirDwing/webpack-lab/tree/antd>
|
|
|
+
|
|
|
+## 注意事项
|
|
|
+
|
|
|
+### 1.最好不要用各类脚手架生成的 webpack 配置
|
|
|
+
|
|
|
+原因有如下几点:
|
|
|
+
|
|
|
+1. 臃肿,夹杂了一大堆没用的第三方npm包,结构混乱, 难维护!!
|
|
|
+2. `webpack`更新速度较快, 现在已经到了 `3.x` 版本了, 很多脚手架还停留在 1.x 或 2.x的阶段
|
|
|
+3. 知其然知其所以然, 不能仅做代码搬运的机器, 这样的话就失去了人的价值了. 只有在频繁地接触和使用过程中才能挖掘更优的配置
|
|
|
+
|
|
|
+### 2.webpack配置最佳实践
|
|
|
+
|
|
|
+个人推荐以一个配置为`base`(基准),其他进行微调.
|
|
|
+
|
|
|
+如, 产品环境配置为:
|
|
|
+
|
|
|
+```js
|
|
|
+// webpack.config.js
|
|
|
+/* eslint-disable import/no-extraneous-dependencies */
|
|
|
+const webpack = require('webpack');
|
|
|
+const path = require('path');
|
|
|
+const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
|
+const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
|
|
+const theme = require('./antd.config');
|
|
|
+
|
|
|
+module.exports = {
|
|
|
+ entry: {
|
|
|
+ app: path.resolve(__dirname, '../src/main.jsx'),
|
|
|
+ vendor: ['react', 'react-dom', 'react-router', 'mobx']
|
|
|
+ },
|
|
|
+ output: {
|
|
|
+ path: path.resolve(__dirname, '../dist'),
|
|
|
+ filename: '[name].js',
|
|
|
+ publicPath: '/'
|
|
|
+ },
|
|
|
+ module: {
|
|
|
+ rules: [
|
|
|
+ {
|
|
|
+ test: /\.jsx?$/,
|
|
|
+ loader: 'babel-loader',
|
|
|
+ exclude: /node_modules/
|
|
|
+ },
|
|
|
+ {
|
|
|
+ test: /\.less$/,
|
|
|
+ loader: ExtractTextPlugin.extract(
|
|
|
+ `${require.resolve('css-loader')}?sourceMap&-autoprefixer!` +
|
|
|
+ `${require.resolve('less-loader')}?{"sourceMap":true,"modifyVars":${JSON.stringify(theme)}}`
|
|
|
+ )
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ resolve: {
|
|
|
+ modules: [
|
|
|
+ 'node_modules',
|
|
|
+ path.resolve(__dirname, '../src')
|
|
|
+ ],
|
|
|
+ extensions: ['.js', '.json', '.jsx', '.css']
|
|
|
+ },
|
|
|
+ plugins: [
|
|
|
+ new webpack.DefinePlugin({
|
|
|
+ 'process.env.NODE_ENV': '"production"'
|
|
|
+ }),
|
|
|
+ // 或灵活配置
|
|
|
+ // new webpack.DefinePlugin({
|
|
|
+ // 'process.env': {
|
|
|
+ // NODE_ENV: JSON.stringify(process.env.NODE_ENV)
|
|
|
+ // }
|
|
|
+ // }),
|
|
|
+ new webpack.optimize.AggressiveMergingPlugin(),
|
|
|
+ new webpack.optimize.CommonsChunkPlugin({
|
|
|
+ name: 'common',
|
|
|
+ filename: 'common.js'
|
|
|
+ }),
|
|
|
+ new webpack.optimize.ModuleConcatenationPlugin(),
|
|
|
+ new webpack.optimize.UglifyJsPlugin({
|
|
|
+ minimize: true,
|
|
|
+ output: {
|
|
|
+ comments: false
|
|
|
+ },
|
|
|
+ compress: {
|
|
|
+ warnings: false,
|
|
|
+ drop_console: false
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ new ExtractTextPlugin('[name].css', {
|
|
|
+ disable: false,
|
|
|
+ allChunks: true
|
|
|
+ }),
|
|
|
+ new HtmlWebpackPlugin({
|
|
|
+ template: path.resolve(__dirname, '../src/index.html')
|
|
|
+ })
|
|
|
+ ]
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+开发环境配置可以是这样去写:
|
|
|
+
|
|
|
+```js
|
|
|
+// webpack.config.dev.js
|
|
|
+const webpack = require('webpack');
|
|
|
+// 引入 base
|
|
|
+const config = require('./webpack.config');
|
|
|
+// 对 base 进行扩展
|
|
|
+module.exports = Object.assign({}, config, {
|
|
|
+ entry: [
|
|
|
+ // 重新完整定义一个 entry, 当然一般情况下是用不着这么做的
|
|
|
+ ],
|
|
|
+ output: Object.assign({}, config.output, {
|
|
|
+ // 仅修改 output 的 publicPath
|
|
|
+ publicPath: 'http://localhost/'
|
|
|
+ }),
|
|
|
+ // 比如, 在开发环境中需要多加一个 plugin
|
|
|
+ plugins: [
|
|
|
+ ...config.plugins,
|
|
|
+ // 该插件仅用于示例
|
|
|
+ new webpack.optimize.ModuleConcatenationPlugin()
|
|
|
+ ],
|
|
|
+ // 加一项新的配置
|
|
|
+ devtools: ''
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+当然你可能觉得这么写性能很低, 但对于只在启动时执行一次的代码来说没有什么, 而且你如果仔细研究一下,比如`webpack-merge`或者其他的, 它们的底层实现也是这样, 还另外套了许多的封装.
|