webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
1.webpack 介绍
模块化思想:
- 按照代码的业务逻辑进行划分,分成一块一块,模块复用化,提高效率。
- 项目按照不同类型的文件,分别进行不同的管理
组件化思想:
组件化思想是对于不同的页面,使用不同的组件,从页面的角度考虑,是否有公共组件,实现组件复用,组件化。(vue、react)
webpack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等)、文件等,并将其转换和打包为合适的格式供浏览器使用。
2. webpack和Grunt和Gulp比较
Webpack和另外两个并没有太多的可比性,Gulp/Grunt是一种能够优化前端的开发流程的工具,而webpack是一种模块化的解决方案,不过Webpack的优点使得Webpack在很多场景下可以替代Gulp/Grunt类的工具。
Grunt和Gulp的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,工具之后可以自动替你完成这些任务。
Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。
3.webpack核心概念
3.1 入口(entry)
入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
entry: {[entryChunkName: string]: string|Array<string>}
// 在多页应用中,(译注:每当页面跳转时)服务器将为你获取一个新的 HTML 文档。页面重新加载新文档,并且资源被重新下载
// 使用 CommonsChunkPlugin 为每个页面间的应用程序共享代码创建 bundle。由于入口起点增多,多页应用能够复用入口起点之间的大量代码/模块,从而可以极大地从这些技术中受益
const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
3.2 输出(output)
配置 output 选项可以控制 webpack 如何向硬盘写入编译文件。注意,即使可以存在多个入口起点,但只指定一个输出配置。
// 单个入口起点
const config = {
output: {
filename: 'bundle.js',
path: '/home/proj/public/assets'
}
};
// 多个入口起点
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
3.3 loader
Loaders是webpack提供的最激动人心的功能之一了。通过使用不同的loader,webpack有能力调用外部的脚本或工具,实现对不同格式的文件的处理,比如说分析转换scss为css,或者把下一代的JS文件(ES6,ES7)转换为现代浏览器兼容的JS文件,对React的开发而言,合适的Loaders可以把React的中用到的JSX文件转换为JS文件。
module.rules
允许你在 webpack 配置中指定多个 loader。 这是展示 loader 的一种简明方式,并且有助于使代码变得简洁。同时让你对各个 loader 有个全局概览,Loaders的配置包括以下几方面:
- test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
- loader:loader的名称(必须)
- include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
- query:为loaders提供额外的设置选项(可选)
load的特性
- loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。
- loader 可以是同步的,也可以是异步的。
- loader 运行在 Node.js 中,并且能够执行任何可能的操作。
- loader 接收查询参数。用于对 loader 传递配置。
- loader 也能够使用 options 对象进行配置。
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
- 除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段。
- 插件(plugin)可以为 loader 带来更多特性。
- loader 能够产生额外的任意文件。
loader列表
3.4 插件(plugins)
插件(Plugins)是用来拓展Webpack功能的,它们会在整个构建过程中生效,执行相关的任务。
- 插件的使用
要使用某个插件,我们需要通过npm安装它,然后要做的就是在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数组)。
const webpack = require('webpack');
module.exports = {
...
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
modules: true
}
}, {
loader: "postcss-loader"
}
]
}
]
},
plugins: [
new webpack.BannerPlugin('版权所有,翻版必究')
],
};
**1. HtmlWebpackPlugin插件**
这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。
npm install --save-dev html-webpack-plugin
plugins: [
new HtmlWebpackPlugin({
template: __dirname + "/app/index.html"//new 一个这个插件的实例,并传入相关的参数
})
],
**2. Hot Module Replacement (HMR)热加载**
它允许你在修改组件代码后,自动刷新实时预览修改后的效果。
3. 其他插件
- OccurenceOrderPlugin :为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
- UglifyJsPlugin:压缩JS代码;
- ExtractTextPlugin:分离CSS和JS文件
4. webpack打包速度优化
// 1.HotModuleReplacementPlugin 热加载模块使用
// 2.选择一个合适的devtool属性值 推荐:cheap-module-eval-source-map
// 3. 代码压缩用ParallelUglifyPlugin代替自带的 UglifyJsPlugin插件。
// 自带的JS压缩插件是单线程执行的,而[webpack-parallel-uglify-plugin](https://github.com/gdborton/webpack-parallel-uglify-plugin)可以并行的执行
new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJS:{
output: {
comments: false
},
compress: {
warnings: false
}
}
})
// 4.CommonsChunkPlugin插件提取公共模块
// 提取公共模块文件
new webpack.optimize.CommonsChunkPlugin({
chunks: ['home', 'detail'],
// 开发环境下需要使用热更新替换,而此时common用chunkhash会出错,可以直接不用hash
filename: '[name].js' + (isProduction ? '?[chunkhash:8]' : ''),
name: 'common'
}),
// 切合公共模块的提取规则,有时后你需要明确指定默认放到公共文件的模块
// 文件入口配置
entry: {
home: './src/js/home',
detail: './src/js/detail',
// 提取jquery入公共文件
common: ['jquery', 'react', 'react-dom']
},
4. webpack使用
4.1 非配置文件命令行命令执行
# webpack非全局安装的情况
node_modules/.bin/webpack 入口文件 出口文件
#webpack 全局安装情况
webpack 入口文件 出口文件
webpack 的全局安装。
# 全局安装webpack
npm install webpack -g
# 将webpack安装到项目中
npm install webpack --save-dev
4.2 webpack配置文件使用
webpack的配置文件,使用vue-cli生成的
// webpack.config.js
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
chunkFilename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
}
}
打包命令,可以使用npm相关配置,完成打包,再项目的pakage.json文件中,对scripts对象进行相关设置即可。
{
"name": "tapp",
"version": "1.0.0",
"description": "A Vue.js project",
"author": "scott",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit",
"build": "node build/build.js" // 修改的是这里,JSON文件不支持注释,引用时请清除
},
"dependencies": {
"axios": "^0.18.0",
"babel-polyfill": "^6.26.0",
"echarts": "^4.1.0",
}
}
4.3 使用webpack构建本地服务器(devServer)
如何让你的浏览器监听你的代码的修改,并自动刷新显示修改后的结果------热加载
其实Webpack提供一个可选的本地开发服务器,这个本地服务器基于node.js(vue-cli使用的是express)构建,可以实现你想要的这些功能,不过它是一个单独的组件,在webpack中进行配置之前需要单独安装它作为项目依赖。(vue-cli默认安装了依赖)
npm install --save-dev webpack-dev-server
webpack-dev-server的配置文件
// devServer服务器
devServer: {
clientLogLevel: 'warning', // LogLevel Possible values are none, error, warning or info (default). 日志级别
// When using the HTML5 History API, the `index.html` page will likely have to be served in place of any `404` responses。替换404请求的页面
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true, // Enable webpack's Hot Module Replacement feature 热加载
contentBase: false, // since we use CopyWebpackPlugin.
compress: true, // Enable gzip compression for everything served 是否启用压缩
host: HOST || config.dev.host, // url
port: PORT || config.dev.port, // 端口
open: config.dev.autoOpenBrowser, // 是否自动打开浏览器
openPage: config.dev.openPage, // 打开浏览器的地址
// 当存在编译器错误或警告时,在浏览器中显示全屏覆盖。默认情况下禁用
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
// 根路径
publicPath: config.dev.assetsPublicPath,
// 启用代URL
proxy: {
'/IntelligentWaterAffairs': {
target: 'http://39.104.178.72:8080/', // 接口域名 //server
changeOrigin: true, //是否跨域
}
},
quiet: true, // necessary for FriendlyErrorsPlugin
// 启用轮询
watchOptions: {
poll: config.dev.poll,
}
}
config/index.js 启用devtool
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-module-eval-source-map',
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
cssSourceMap: true
5. Babel
- Babel是什么?
Babel其实是一个编译JavaScript语言的平台。 - Babel的目的是要达到那种效果?
- 让你能使用最新的JavaScript代码(ES6,ES7...),而不用管新标准是否被当前使用的浏览器完全支持;
- 让你能使用基于JavaScript进行了拓展的语言,比如Vue的JSX;
- Babel是怎样配置的?
babel的配置选项放在一个单独的名为 ".babelrc" 的配置文件中。
- 安装babel
npm install --save-dev babel-loader babel-core babel-preset-env babel-plugin-transform-runtime babel-plugin-istanbul babel-polyfill babel-preset-stage-2 babel-register
- babelrc文件配置
{
"presets": [
["env", { "modules": false }],
"stage-2"
],
"plugins": ["transform-runtime"],
"comments": false,
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": [ "istanbul" ]
}
}
}
3.webpack.config.js 配置
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
参考资料: 部分内容来源于参考资料。
https://www.webpackjs.com/concepts/
https://segmentfault.com/a/1190000006178770#articleHeader5