手动构建Webpack开发环境
WebPack基础教程
Webpack开发环境配置
webpack+sass+babel+postcss配置
Webpack多页面配置
WebPack基础教程
WebPack是目录前端用于构建自动化开发的一款非常流行的工具,与之前的gulp和grunt功能非常相似,它们都是一款通过JavaScript来构建Web网站的自动化工具!
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
我们可以通过下面的一张图来完理解这一部分的功能
webpack可以全一切变得都非常简单,它提倡模块化进行开发,拼提供通过工具的操作简化和提高前端开发工作
入门
WebPack是基于NodeJs平台运行的,所以,在合作Webpack之前,请先保证自己的开发环境下有NodeJs的运行环境
-
安装Webpack
目前我们所使用的Webpack的版本为webpack3的版本,最新的版本为webpak4的版本,因最新版本对一些插件不支持,并有部分不稳定的情况,我们此处以webpack3为版本进行讲解
$ cnpm install webpack@3 -g
说明:上面的代码是全局安装webpack3的版本
-
编写JS代码,通过webpack来进行打包处理
我们在上面的代码当中,创建了一个app.js和bar.js 然后在app.js中通过ES6的模块化开发,引入了这个文件
正常情况下,我们是不可能在浏览器中使用export与import等这些关键字的,现在,我们可以在这里通过webpack来打印处理一下
$ webpack app.js bundle.js
说明:好面的代码是将app.js通过webpack打包以后,翻译成bundle.js,打包完成以后,我们就可以在浏览器中正常使用这个JS文件了
- 引入文件,查看效果
通过上面的入门,我们发现,其实,使用Webpack并不是很验,至少我们可以得出以后结论
- webpack可以将es6的代码转换成我们浏览器使用的代码(正常情况下,es6的代码需要在nodejs环境下面才能够运行)
- 我们通过webpack可以在进行模块化开发,同时,在模块化开发的过程当中,把这些模块化的代码运行于浏览器(以前的模块化开发,我们只是针对Nodejs的平台)
在这里,我们的Nodejs的一切比较良好的模块化开发特性,以及ES6的一些高效语法就都可以在这里进行使用了
WebPack.config.js的配置
在上面的入门代码里面,我们知道,如果要把我们的代码进行打包处理,则需要手动的去执行一条命令,但是这样操作非常麻烦 ,我们不可能每次更改代码以后都去手动的执行一次命令,这个时候,我们可以通过一个配置文件,来配置我们的Webpack操作
Webpack的配置文件,我们一般命名为webpack.config.js这个文件,在这个文件里面,有四大部分,如下:
- 入口(entry)
- 出口(output)
- loader
- 插件(plugins)
入口(entry)
首先,我们先在项目的根目录下面,创建一个webpack.config.js的文件,然后打开文件,编写如下代码
module.exports = {
entry: './src/app.js'
};
说明:上面的
./src/app.js
代表的就是这个程序的入口文件
出口(output)
output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件。你可以通过在配置中指定一个 output
字段,来配置这些处理过程:
const path = require('path');
module.exports = {
entry: './src/app.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
}
};
在上面的代码中,我们通过
output.filename
和output.path
属性,来告诉 webpack bundle 的名称,以及我们想要生成到哪里。就像之前的入门里面,我们使用
webpack app.js bundle.js
一样,前面是入口文件,后面是出口文件
loader
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
例如,我可以让webpack来处理scss的预处理CSS文件,也可以让webpack来处理vue的文件,这都是webpack所具务的功能,但是,webpack如果想要使用这些功能,必须要使用第三方的模块,而这些第三方的模块,我们就叫做loader
注意,loader 能够
import
导入任何类型的模块(例如.css
文件),这是 webpack 特有的功能,其他打包程序或任务执行器的可能并不支持。我们认为这种语言扩展是有很必要的,因为这可以使开发人员创建出更准确的依赖关系图。
在配置loader的时候,里面有两个必填属性,一个是test,一个是use属性:
test
属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。use
属性,表示进行转换时,应该使用哪个 loader。
const path = require('path');
const config = {
entry: './src/app.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.scss/, use: 'sass-loader' }
]
}
};
module.exports = config;
以上配置中,对一个单独的 module 对象定义了 rules
属性,里面包含两个必须属性:test
和 use
。这告诉 webpack 编译器,如下信息:
“嘿,webpack 编译器,当你碰到「在
require()
/import
语句中被解析为 ‘.scss’ 的路径」时,在你对它打包之前,先使用sass-loader
转换一下。”
在此处说明一下,webpack的loader必须配置在module.rules这个属性里面!
插件 plugins
插件在此得先不作说明,后期案例具体说明
Webpack与Babel的结合
我们刚刚说过一件事情,就是我们在使用webpack的时候,可以将我们的es6代码的模块化运用得非常好,但是,有些时候,浏览器必不能识别所有的es6代码,这个时候,我们就需要使用一个第三方模块,来处理我们的es6代码,而这个模块就是babel
Babel是一款非常浏览的代码翻译工具,无论是现在的ES6,还是Vue或React,这些大名鼎鼎的框架都是要基于Babel的,如果脱离了Babel,这些框架运行起来会非常困难
首先,我们要知道 Babel的第三方模块如果去使用。在Babel的中文官网当中,我们可以找到babel在webpack中的配置(在此处说明一下,babel这个第三方模块不只是运行在webpack中,还可以运行在其它的平台),具体使用步骤如下:
-
安装
$ cnpm install --save-dev babel-loader babel-core
-
通过config进行配置
module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" } ] }
说明:上面的代码的意思就是告诉webpack,如果碰到.js的文件,就使用第三方的模块
babel-loader
来进行处理一下,但是并不是所有的js文件都要处理,在node_modules
这里面的文件就不要处理了 -
配置代码的处理方式
我们刚刚都说过了,我们的babel是一个代码翻译工具,它会把我们的代码翻译成我们浏览器认识的语言,可是,我们总要告诉babel我们所使用的语言到底是什么语言吧,这个时候,我们就需要添加一个babel的专用配置文件
我们需要在项目的根目录下面创建一个
.babelrc
这个文件,然后在这个文件当中,配置如下信息:{ "presets": ["env"] }
说明:我们看到了一个presets这个选项后面根着的是env,这个env代表的是根据当前的运行环境自动选择编译项,而这个运行环境是什么呢,babel也不知道,所以,我们要告诉babel,这个时候,我们找到项目的package.json文件,配置一下当前的运行环境
{ "name": "webpack04", "version": "1.0.0", "description": "webpack手动配置项", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --config webpack.config.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "babel-core": "^6.26.0", "babel-loader": "^7.1.4", "webpack": "^3.11.0" }, "browserslist": [ "defaults", "not ie < 11", "last 2 versions", "> 1%", "iOS 7", "last 3 iOS versions" ] }
说明:在上面的代码当中,我们看到了一个配置项browerslist这个,在这里,我们配置了一些信息,其中的信息 是默认配置,然后非IE11等信息
-
配置代码的stage环境
现在的ECMASCript标准已经发展到es8了,所以,我们在书写JS代码的时候,可以使用一些比较新的特性,例如我们的异步处理当中的
async
与await
这些方法。如果要让我们的浏览器支持async与await这些方法,仅仅是通过webpack和babel的一些常规处理方法是不行的,我们需要使用babel-preset-stage-0
与babel-polyfill
这两个插件说明:Babel 包含一个可自定义 regenerator runtime 和 core-js的 polyfill .
它会仿效一个完整的 ES2015+ 环境,并意图运行于一个应用中而不是一个库/工具。这个 polyfill 会在使用
babel-node
时自动加载。这意味着你可以使用新的内置对象比如
Promise
或者Map
, 静态方法比如Array.from
或者Object.assign
, 实例方法比如Array.prototype.includes
和生成器函数(提供给你使用 regenerator 插件)。为了达到这一点, polyfill 添加到了全局范围,就像原生类型比如String
一样。-
第一步:先安装
babel-preset-stage-0
与babel-polyfill
$ cnpm install babel-preset-stage-0 babel-polyfill --save-dev
-
第二步:修改webpack.config.js中的entry入口
var config={ entry: ["babel-polyfill", path.join(__dirname, "./src/main.js")] //.... } module.exports=config;
-
第三步:修改babel的配置文件
在
.babelrc
的配置文件中,修改成如下:{ "presets": [ "env", "stage-0" ] }
通过上面的配置以后,我们就可以正常的使用ES6里面新特性了
-
webpack生成编译文件
当我们配置好webpack的配置文件以后,所以的操作我们就都可以交给webpack来处理了,这个时候,我们在进行编译的过程当中,要让webpack来使用我们的配置文件,这个时候,需要执行如下命令
$ webpack --config webpack.config.js
命令执行成功以后,就会在指定的目录生成我们的目录文件,这个时候,我们可以把这条命令写在package.json这个文件里面
在package.json的文件里面,我们在scripts
这个节点里面,添加如下代码:
{
"name": "webpack04",
"version": "1.0.0",
"description": "webpack手动配置项",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"webpack": "^3.11.0"
},
"browserslist": [
"defaults",
"not ie < 11",
"last 2 versions",
"> 1%",
"iOS 7",
"last 3 iOS versions"
]
}
上面的build就是我们添加的自定义命令,添加自定义完成以后,我们就可以在控制台输入
npm run build
来执行上面的命令,最终会执行我们的webpack的打包操作
webpack开发环境与生产环境
我们在使用webpack进行打包配置的时候,我们不可能一直去执行生成的操作,然后去把生成的bundle.js这个文件引入到我们的HTML文件当中,这个的开发非常麻烦,也非常繁琐,这个时候,Webpack本身也考虑到这个问题
官方针对这种情况推出了一个小型的基于express的迷你http服务器,可以让我们开发的网页运行在http的服务器下面,然后做到实时编写,实时编译,这个时候,效果就会非常高!这一种高效的环境,我们叫做webpack的开发环境
Webpack的开发环境当中的http服务器依赖于webpack-dev-server,从名字当中我们可以看出这是webpack的开发服务器,接下来的过程里面,我们来了解一下如何学配置webpack的开发环境
-
首先,我们需要安装webpack-dev-server
$ cnpm install webpack-dev-server@2 --save-dev
说明:上面的webpack-dev-server我们使用的是2的版本,目前最新版为3
-
在package.json的文件当中,添加开发环境的启动命令!
我们会在package.json的
scripts
的脚本下面添加如下命令"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --config webpack.config.js", "dev":"webpack-dev-server --config webpack.config.js" }
说明:上面的dev就是我们配置的启动名称,后面的代码就是启动命令
通过上面的dev代码,我们会发现,这个时候的打包命令由webpack变成了webpack-dev-server,这个时候,我们会在这个地方以webpack-dev-server的方式来打包,但是,我们需要弄清楚一点,这个时候,我们使用的配置文件都是webpack.config.js这个文件,而我们的build命令与dev的命令又是不一样的,这个时候,我们就需要在webpack.config.js的文件当中做出一些区分,具体代码如下所示:
const path = require('path'); const ExtractPlugin = require('extract-text-webpack-plugin'); const webpack = require('webpack'); const HTMLPlugin = require("html-webpack-plugin"); //根据启动参数去判断是否等于development,如果是就是开发环境,如果不是,就是生产环境 var isDev = process.env.NODE_ENV === "development" ? true : false; var config = { entry: ["babel-polyfill", path.join(__dirname, "./src/main.js")], output: { path: path.join(__dirname, "./dist"), filename: "bundle.js" }, module: { rules: [{ test: /\.js$/, use: ["babel-loader"], include: path.join(__dirname, "./src") }, { test: /\.css$/, use: [ "style-loader", "css-loader" ] }, { test: /\.scss$/, use: [ "style-loader", "css-loader", { loader: "postcss-loader", options: { config: { path: path.join(__dirname, "./postcss.config.js") } } }, "sass-loader" ] }, { test: /\.(jpg|jpeg|png|gif|svg|bmp)$/, use: [{ loader: "url-loader", options: { limit: 1000, name: "[name]-aaa.[ext]" } }] } ] }, plugins: [ new HTMLPlugin({ template: "index.html", //模板文件的位置 inject: true }) ] } if (isDev) { config.devServer = { host: "0.0.0.0", port: 8888, overlay: { error: true } } } module.exports = config;
说明:在上面的代码当中,我们看到我们使用了一个叫process.env.NODE_ENV的文件来判断当前的环境是否是开发环境,这个时候,我们如何去区分他们的环境呢?
我们刚刚在package.json的文件当中,通过"build"与"dev"的两个命令来区分,但是,这只是启动方式改变了,后面的配置文件还是同一个,为了区分这个环境,我们需要一个第三方的模块 cross-env,这个模块可以在启动命令的前面添加启动参数,这个启动参数会传递到nodejs的运行环境当中
现在,我们安装cross-env以区分不同的启动方式
$ cnpm install cross-env --save-dev
安装完成以后,我们把上面的
scripts
中的启动命令改成如下:"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "cross-env NODE_ENV=production webpack --config webpack.config.js", "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js" }
在上面的代码里面, 我们分别在启动命令前面用cross-env来区分NODE_ENV到底是
production
还是development
区分了环境以后,我们用了一个变量isDev来判断,如果是开发环境,我们在后面配置了一个devServer那么,我们可以在里面配置它的服务器地址,服务器端口,服务器。