现今的web,都很丰富,它们拥有着复杂的JavaScript代码,一大堆依赖包,为了简化开发的复杂度,前端世界出现了很多很好的实践方法。
这些改进确实大大提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,而手动处理是非常繁琐的,webpack应运而生!
模块打包机:它做的事情就是,分析你的项目结构,找到javascript模块,以及其它的一些浏览器不能直接运行的拓展语言(less,sass,jsx),并将其打包为合适的格式,供浏览器使用。
其实webpack跟它们俩没什么可比性,不是一回事。
npm install -g webpack //全局
npm install --save-dev webpack //当前目录
npm install --save-dev webpack@version
webpack <entry.js> <result.js> //其中entry.js是入口文件,result.js是打包后的输出文件
如果在终端中进行复杂的操作,还是不太方便且容易出错的.Webpack拥有很多其它的比较高级的功能(比如说本文后面会介绍的loaders和plugins),这些功能其实都可以通过命令行模式实现,但是正如已经提到的,这样不太方便且容易出错的,一个更好的办法是定义一个配置文件,这个配置文件其实也是一个简单的JavaScript模块,可以把所有的与构建相关的信息放在里面
webpack --config webpack.custom.config.js
npm可以引导任务执行,对其进行配置后可以使用简单的npm start命令来代替这些繁琐的命令。
//package.json
"scripts": {
"start": "webpack" //配置的地方就是这里啦,相当于把npm的start命令指向webpack命令
},
常用的命令:
项目中静态资源文件较多,使用配置文件进行打包方便很多,这个文件告诉webpack要做什么。
基本配置
module.exports = {
entry: "./app/entry", //string | object | array 应用开始执行,webpack开始打包
output: {
path: path.resolve(__dirname, "dist"), //string
filename: 'bundle.js',
publickPath: "",
library: '',
library: 'umd',
...
},
module: { //模块配置
rules: [
//模块规则【配置loader,解析器等选项
]
},
resolve: { //解析模块请求的选项
modules: [],
extensions: ['', '.js', '.json', '.scss'],
alias: {
AppStore: 'js/stores/AppStores.js',
...
}
},
devtool: "source-map",
context: "",
target: "",
externals: [],
devServer: [],
plugins: [],
performance: {},
...
}
它是高度可以配置的,但是,在开始前,你需要先理解四个核心概念: 入口(entry), 输出(output), loaders, 插件(plugins).
entry
webpack 将创建所有应用程序的依赖关系图表(dependency graph).图表的起点被称为入口起点(entry point).入口起点告诉webpack从哪里开始,并遵循着依赖关系图表知道要打包什么。可以认为是app的第一个启动文件。module.exports = {
entry: './path/to/my/entry/file.js'
}
output
将所有的资源归拢在一起后,还需要告诉webpack在哪里打包应用程序,就是如何处理归拢在一起的代码。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'
}
};
loaders
鼎鼎大名的loaders登场了!
Loaders是webpack中最让人激动人心的功能之一了。通过使用不同的loader,webpack通过调用外部的脚本或工具可以对各种各样的格式的文件进行处理,比如说分析JSON文件并把它转换为JavaScript文件,或者说把下一代的JS文件(ES6,ES7)转换为现代浏览器可以识别的JS文件。或者说对React的开发而言,合适的Loaders可以把React的JSX文件转换为JS文件。module.exports = {
entry: './path/to/my/entry/file.js'
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [
["es2015", {"modules": false}],
"stage-0",
"react"
],
plugins: [
"transform-async-to-generator",
"transform-decorators-legacy"
]
}
},
]
}
}
plugins
插件(Plugins)是用来拓展Webpack功能的,它们会在整个构建过程中生效,执行相关的任务。 Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个,插件并不直接操作单个文件,它直接对整个构建过程其作用。
Webpack有很多内置插件,同时也有很多第三方插件,可以让我们完成更加丰富的功能。
要使用某个插件,我们需要通过npm安装它,然后要做的就是在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数组)继续看例子,我们添加了一个实现版权声明的插件。 const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');
const config = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{test: /\.(js|jsx)$/, use: 'babel-loader'}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/build",
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.json$/,
loader: "json"
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel'
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style', 'css?modules!postcss')
}
]
},
postcss: [
require('autoprefixer')
],
plugins: [
new HtmlWebpackPlugin({
template: __dirname + "/app/index.tmpl.html"
}),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin(),
new ExtractTextPlugin("style.css")
]
}
开发总是离不开调试,如果方便调试,可以提高开发效率,一般打包的代码不容易识别出错的位置,Source Maps就是来帮我们解决这个问题的。
在webpack中,配置devtool属性。来控制source maps
devtool的值有四种:
devtool | 配置结果 |
---|---|
source-map | 在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包文件的构建速度; |
cheap-module-source-map | 在一个单独的文件中生成一个不带列映射的map,不带列映射提高项目构建速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便; |
eval-source-map | 使用eval打包源文件模块,在同一个文件中生成干净的完整的source map。这个选项可以在不影响构建速度的前提下生成完整的sourcemap,但是对打包后输出的JS文件的执行具有性能和安全的隐患。不过在开发阶段这是一个非常好的选项,但是在生产阶段一定不要用这个选项; |
cheap-module-eval-source-map | 这是在打包文件时最快的生成source map的方法,生成的Source Map 会和打包后的JavaScript文件同行显示,没有列映射,和eval-source-map选项具有相似的缺点; |
正如上表所述,上述选项由上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的构建速度的后果就是对打包后的文件的的执行有一定影响。
开发环境推荐使用eval-source-map 生产环境使用:cheap-module-eval-source-map方法构建速度更快
想不想让你的浏览器监测你的代码的修改,并自动刷新修改后的结果,其实Webpack提供一个可选的本地开发服务器,这个本地服务器基于node.js构建,可以实现你想要的这些功能,不过它是一个单独的组件,在webpack中进行配置之前需要单独安装它作为项目依赖
npm install --save-dev webpack-dev-server
devserver作为webpack配置选项中的一项,具有以下配置选项
devServer | 功能描述 |
---|---|
contentBase | 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到"public"目录) |
port | 设置默认监听端口,如果省略,默认为"8080" |
inline | 设置为true,当源文件改变时会自动刷新页面 |
colors | 设置为true,使终端输出的文件为彩色的 |
historyApiFallback | 在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html |
module.exports = {
devtool: 'eval-source-map', entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
}, devServer: {
contentBase: "./public",//本地服务器所加载的页面所在的目录
colors: true,//终端中输出结果为彩色
historyApiFallback: true,//不跳转
inline: true,//实时刷新
port: 3000
}
}
关于Webpack本文讲述得仍不完全,不过相信你看完后已经进入Webpack的大门,能够更好的探索其它的关于Webpack的知识了。