目标
- webpack/babel工具的原理,配置详解及多场景实实践
- 函数式编程
知识要点
webpack
构建步骤
- 分不同环境的config,包含了对应的一些配置
dev.env.js
'use strict'
const merge = require('webpack-merge')//使用webpack-merge工具去合并配置
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
})
- 不同环境的webpack.config.js阿配置,以及prod环境构建文件build.js的配置
其中utils.js 为构建loader的工具文件,webpack.base.conf.js为所有环境初始化的相同配置的文件,其它webpack的config文件就是对应相应的环境的不同配置
拿build.js和webpack.base.conf.js代码来观看
build.js
'use strict'
require('./check-versions')() // 检查node和npm版本
process.env.NODE_ENV = 'production' // 指定环境变量
const ora = require('ora') // 一个美美的loading插件
const rm = require('rimraf') // rm -rf Node版本的unix命令
const path = require('path') // node自带的文件路径插件
const chalk = require('chalk') // 控制台高亮
const webpack = require('webpack')
const config = require('../config') // 配置入口
const webpackConfig = require('./webpack.prod.conf') // webpack配置
const spinner = ora('building for production...')
spinner.start()
// config 三套环境 并行并且互相隔离的入口
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, (err, stats) => {
spinner.stop()
if (err) throw err
// webpack编译的开始
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'))
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won't work.\n'
))
})
})
webpack.dev.conf.js
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
// dev.conf 的配置 和 base.conf的配置合并
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
// cheap-module-eval-source-map is faster for development
// 原理
devtool: config.dev.devtool,
// these devServer options should be customized in /config/index.js
devServer: {
clientLogLevel: 'warning',
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true,
contentBase: false, // since we use CopyWebpackPlugin.
compress: true,
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable, // 面试题:如何本地项目去做一些多端口服务的代理转发
quiet: true, // necessary for FriendlyErrorsPlugin
watchOptions: {
poll: config.dev.poll,
}
},
// 微内核
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
// 生成html模板文件
// 面试题: 如何利用webpack去做依赖锁定?
// 锁依赖固定板本 script
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
// copy custom static assets
// 面试题:静态文件的移动&赋值
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
module.exports = new Promise((resolve, reject) => {
portfinder.basePort = process.env.PORT || config.dev.port
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
// publish the new Port, necessary for e2e tests
process.env.PORT = port
// add port to devServer config
devWebpackConfig.devServer.port = port
// Add FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
},
onErrors: config.dev.notifyOnErrors
? utils.createNotifierCallback()
: undefined
}))
resolve(devWebpackConfig)
}
})
})
那么webpack的打包到底能做到什么事情呢?
webpack.*.config.js作用总结
从module.exports的每个属性讲解
-
context: 基础目录,绝对路径,用于从配置中解析入口点(entry point)和 加载器(loader)。
-
entry: 入口文件的配置,webpack会根据入口文件去找到所有import, requrie的依赖文件,并进行接下的识别,加载,编译,优化。
-
output: webpack把编译好的文件输出的地址,可以配置输出的文件名,资源前缀
-
devtool:配置是否生成sourceMap
-
devServer: 配置local启动时的host, port, 是否压缩,log的水平,是否启动默认打开浏览器,代理api的proxy等等
-
resolve: 用于配置需要扫描的文件类型,和一些路径或者文件的别名配置
-
module 主要的rules数组: 包含了对不同文件例如.vue,.js, .css, 图片对应loader的配置
-
resolveLoader: 主要配置自己写的loader的路径在哪里,这样可以在rule里面配置自己的loader
-
plugins: 配置插件在编译的每个阶段进行相应的控制与优化
- DefinePlugin : 配置编译时的全局变量
- HtmlWebpackPlugin: 生成html模板文件,把生成的scrprit 配置注入的index.html,可以利用webpack去做依赖锁定,配置特定script
- CopyWebpackPlugin : 静态文件的移动&赋值
-
node: 这些选项可以配置是否 polyfill 或 mock 某些 Node.js 全局变量。
此功能由 webpack 内部的
NodeStuffPlugin插件提供。
build.js文件 webpack打包启动文件
- rm : 先删除原来的dist对应的文件夹目录
- webpack:传入对应的webpack.config.js文件进行相应的打包,最后callback来判断打包是否成功,并控制台输出结果
优化场景
看我分享的脑图
函数式编程
特点
1. Vue3 React16.8 全面化函数式的推动
2. 函数式编程可以使得代码单元相对更加独立 - tree shaking过程更顺畅,更方便做UT
3. 减少了对this的依赖,减轻了开发人员对于指向问题的困惑
4. js天生友好函数式:ramda、loadsh
概念
1. 一种抽象运算过程
2. 函数式的函数并非对于过程运算,函数的映射
3. 幂等 - 相同的输入始终得到相同的输出
纯函数
let arr = [1, 2, 3, 4, 5];
arr.slice(0, 3); // [1, 2, 3]
arr.slice(0, 3); // [1, 2, 3]
arr.splice(0, 3); // [1, 2, 3]
arr.splice(0, 3); // [4, 5]
对于系统的改造
// 不纯的
let min = 18;
let limit = age => age > min;
// 纯纯的
let limit = age => age > 18;
对于大型系统来说,对于外部状态的依赖,会大大的提高系统复杂性
- 问题: 18被硬编码到了函数内部的,造成了功能拓展的局限
高阶函数HOC
定义:
- 函数作为参数被传递到另一个函数中
- 函数作为返回值被另外一个函数返回
let fn = arg => {
let outer = "outer";
let innerFn = () => {
console.log(outer);
console.log(arg);
}
return innerFn;
}
let closure = fn(18);
// 闭包
函数柯里化
传递给函数一部分参数用于功能调用,让他返回一个函数去处理剩下的参数
let add = (x, y) => x + y;
// 柯里化后
let add = x => (y => x + y);
let add2 = add(2);
let add200 = add(200);
add2(2); // 2 + 2 add(2)(2)
add200(50); // 200 + 50
// 回到上面的limit, 纯函数化
let limit = min => (age => age > min);
let limit18 = limit(18);
limit18(20); // true
是一种预加载方式
- 问题 包心菜代码的产生h(g(f(x)));
#### 组合
> 通过更优雅的方式实现纯函数的解耦
```js
let compose = (f, g) => (x => f(g(x)));
let add1 = x => x + 1;
let mul5 = x => x * 5;
compose(mul5, add1)(2); // 15
// 面试题 - 数组长度未知的情况下,拿到最后一项
let first = arr => arr[0];
let reverse = arr => arr.reverse();
let last = compose(first, reverse);
last([1, 2, 3, 4, 5]); // 5
```
补充知识点
webpack
思考一个问题,webpack的配置如此繁多,如何才可以学好它呢。我觉得分为以下几点
- 需要熟知webpack的配置属性有那些,能做到什么样的事情,不需要去每一个loader, 插件都需要了解
- 了解如何去做各种优化,它涉及的点在哪里
- 知道知识来源路径在哪,在哪可以找到对应的文档去,了解,解决问题
所以我总结了一个语雀脑图,包括wepack的配置,优化,demo, loader, 插件,好的学习文章,包含了知识url索引
www.yuque.com/docs/share/…(密码:ia93) 《webpack》
后续会不断更新知识要点