随着前端的迅速发展,web项目复杂度也是越来越高。为了便捷开发和利于优化,将一个复杂项目拆分成一个个小的模块,于是模块化开发出现了。但是由于缺乏规范化管理,出现了很多种模块化规范,从针对nodejs的commonjs规范,到针对浏览器端的CMD、AMD,终于在ES6里规范了前端模块化。
前端构建工具
虽然前端开发在模块化进程上搞得风生水起,但是有个问题就是:源代码无法直接运行,必须通过构建工具转换后才可以正常运行。基于nodejs常见的构建工具有gulp、fis3、webpack。
gulp
Gulp是一个基于流的自动化构建工具。 Gulp 被设计得非常简单,只通过下面5种方法就可以支持几乎所有构建场景:
1.通过 gulp.task注册一个任务;
2.通过 gulp.run 执行任务;
3.通过 gulp.watch 监听文件的变化;
4.通过 gulp.src 读取文件:
5.通过 gulp.dest 写文件。
Gulp的优点是好用又不失灵活,既可以单独完成构建,也可以和其他工具搭配使用 。其缺点是集成度不高,要写很多配置后才可以用,无法做到开箱即用 。
fis3
Fis3 是一个来自百度的国产构建工具。相对于Gulp只提供了基本功能的工具,Fis3集成了Web开发中的常用构建功能,如下所述。
1.读写文件: 通过 fis.match 读文件,release 配置文件的输出路径。
2.资源定位: 解析文件之间的依赖关系和文件位置。
3.文件指纹: 在通过 useHash 配置输出文件时为文件 URL 加上 md5 戳,来优化浏览器的缓存。
4.文件编译: 通过 parser 配置文件解析器做文件转换,例如将 ES6 编译成 ES5。
5.压缩资源: 通过 optimizer 配置代码压缩方法。
6.图片合并: 通过 spriter 配置合并 css 里导入的图片到一个文件中,来减少 Hπp 请求数。
Fis3的优点是集成了各种 Web 开发所需的构建功能,配置简单、开箱即用 。
Fis3 是一种专注于 Web 开发的完整解决方案,如果将 Gulp 比作汽车的发动机, 则可以将 Fis3 比作 一辆完整的汽车。
webpack
Webpack 是一个打包模块化 JavaScript 的工具,在 Webpack 里一 切文件皆模块,通过 Loader转换文件,通过 Plugin注入钩子,最后输出由多个模块组合成的文件。 Webpack专注于构建模块化项目。
Webpack的优点是 :
1.专注于处理模块化的项目,能做到开箱即用、 一步到位:
2.可通过 Plugin 扩展,完整好用又不失灵活 ;
3.使用场景不局限于 Web 开发:
4.社区庞大活跃 ,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展:
5.良好的开发体验 。
Webpack的缺点是只能用于采用模块化开发的项目 。
webpack 常见api简介
webpack的工作就是把我们的静态资源模块通过递归形成依赖关系图,然后将这些模块打包成一个或多个 bundle文件。
它的核心api是entry、module(loader)、plugin、output、mode。接下来我们看一下这些api的功能及用法。
entry 入口
入口起点:构建依赖的开始,通过该起点文件寻找处理依赖
module.exports = {
entry: './path/to/my/entry/file.js'//字符串形式
entry: ['./path/to/my/entry/file.js','./path/to/my/entry/file1.js']//数组形式
entry: {
name:'./path/to/my/entry/file.js',
name1:'./path/to/my/entry/file1.js'
}//对象形式
};
output 出口
output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js',
filename: '[name].js',//多出口
publicPath: "http://cdn.example.com/assets/[hash]/",//cdn + hash
}
};
loader 文件处理
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
module.exports = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
}
}
plugins 插件
插件的使用范围从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。通过使用 new 操作符来创建它的一个实例。
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
module.exports = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
mode 模式
通过mode参数配置,开启开发或者生产环境下的webpack内置优化。
module.exports = {
mode: 'production' //development
};
resolve 解析
设置模块如何被解析。
1.resolve.alias
import Utility from '../../utilities/utility';
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/')
}
使用alias配置别名,可以按下面方式引用
import Utility from 'Utilities/utility';
2.resolve.modules
webpack 解析模块时应该搜索的目录
modules: [path.resolve(__dirname, "src"), "node_modules"]
webpack使用指南
配置导出
webpack是需要传入一个配置对象(configuration object)。可以通过两种方式之一:终端或Node.js。
除了导出单个配置对象,还有可以有其他导出方式:
1.导出函数
module.exports = function(env, argv) {
return {
mode: env.production ? 'production' : 'development',
devtool: env.production ? 'source-maps' : 'eval',
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: argv['optimize-minimize'] // 只有传入 -p 或 --optimize-minimize
})
]
};
};
2.导出promise
webpack 将运行由配置文件导出的函数,并且等待 Promise 返回。便于需要异步地加载所需的配置变量。
module.exports = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
entry: './app.js',
/* ... */
})
}, 5000)
})
}
3.导出多个配置对象
运行 webpack 时,所有的配置对象都会构建。例如,导出多个配置对象,对于针对多个构建目标(例如 AMD 和 CommonJS)打包一个 library 非常有用。
module.exports = [{
output: {
filename: './dist-amd.js',
libraryTarget: 'amd'
},
entry: './app.js',
mode: 'production',
}, {
output: {
filename: './dist-commonjs.js',
libraryTarget: 'commonjs'
},
entry: './app.js',
mode: 'production',
}]
devServer 开发中
1.contentBase
告诉服务器从哪里提供内容。只有在你想要提供静态文件时才需要。devServer.publicPath 将用于确定应该从哪里提供 bundle,并且此选项优先。
默认情况下,将使用当前工作目录作为提供内容的目录,但是你可以修改为其他目录:
contentBase: path.join(__dirname, "public")//可以访问publick文件夹下文件
contentBase: [path.join(__dirname, "public"), path.join(__dirname, "assets")]
contentBase: false
2.publicPath
此路径下的打包文件可在浏览器中访问。publicPath 总是以斜杠(/)开头和结尾
publicPath: "/assets/" //将打包后文件放入assets文件夹下,并可以通过浏览器访问
3.host
host: "0.0.0.0" //服务器外部可访问
4.hot
启用 webpack 的模块热替换特性
5.proxy
proxy: {
"/api": {
target: "https://other-server.example.com",
pathRewrite: {"^/api" : ""},//重写url
secure: false,//https
}
}
//也可以通过context混合书写
proxy: [{
context: ["/auth", "/api"],
target: "http://localhost:3000",
}]
webpack优化
待更新
webpack工作流程
Webpack 的构建流程可以分为以下三大阶段:
1.初始化
启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler。
2.编译
**:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容, 再找到该Module 依赖的 Module,递归地进行编译处理 。
在编译阶段中,最重要的事件是 compilation,因为在 compilation 阶段调用了Loader, 完成了每个模块的转换操作。在 compilation 阶段又会发生很多小事件。
3.输出
将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中 。