入门 Webpack,看这篇就够了
入门 Webpack,看这篇就够了
2018年8月25日更新,目前 webpack 已经更新值 4.17.1 ,本文所用到的各种库或多或少有些过时,跟着代码操作下来可能会遇到各种问题,不过 webpack 的主体思想没变,所以还是希望本文对新学 webpack 的你,有所帮助。此外用基于 webpack 4.17.1 写了一个简单的demo,如果遇到啥问题,可以参考,之后应该会逐步来完善这个demo,如果有啥通用的想实现的功能,也可以在里面提 issue
写在前面的话
阅读本文之前,先看下面这个webpack的配置文件,如果每一项你都懂,那本文能带给你的收获也许就比较有限,你可以快速浏览或直接跳过;如果你和十天前的我一样,对很多选项存在着疑惑,那花一段时间慢慢阅读本文,你的疑惑一定一个一个都会消失;如果你以前没怎么接触过Webpack,而你又你对webpack感兴趣,那么动手跟着本文中那个贯穿始终的例子写一次,写完以后你会发现你已明明白白的走进了Webpack的大门。
一个基础的webpack配置文件
// 一个常见的`webpack`配置文件
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
//已多次提及的唯一入口文件
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/build",
filename: "bundle-[hash].js"
},
devtool: 'none',
devServer: {
contentBase: "./public", //本地服务器所加载的页面所在的目录
historyApiFallback: true, //不跳转
inline: true,
hot: true
},
module: {
rules: [{
test: /(.jsx|.js)$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
}, {
test: /.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [{
loader: "css-loader",
options: {
modules: true,
localIdentName: '[name]__[local]--[hash:base64:5]'
}
}, {
loader: "postcss-loader"
}],
})
}
}
]
},
plugins: [
new webpack.BannerPlugin('版权所有,翻版必究'),
new HtmlWebpackPlugin({
template: __dirname + "/app/index.tmpl.html" //new 一个这个插件的实例,并传入相关的参数
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin(),
new ExtractTextPlugin("style.css")
]
};
什么是WebPack,为什么要使用它?
为什要使用WebPack
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
现今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度,前端社区涌现出了很多好的实践方法
① 模块化开发(import,require)
② 预处理(Less,Sass,ES6,TypeScript……)
③ 主流框架脚手架支持(Vue,React,Angular)
④ 庞大的社区(资源丰富,降低学习成本)
这些改进确实大大的提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,而手动处理又是非常繁琐的,这就为WebPack类的工具的出现提供了需求。 github地址
WebPack和Grunt以及Gulp相比有什么特性
其实Webpack和另外两个并没有太多的可比性,Gulp/Grunt是一种能够优化前端的开发流程的工具,而WebPack是一种模块化的解决方案,不过Webpack的优点使得Webpack在很多场景下可以替代Gulp/Grunt类的工具。
Grunt和Gulp的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,工具之后可以自动替你完成这些任务。
Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。
如果实在要把二者进行比较,Webpack的处理速度更快更直接,能打包更多不同类型的文件。
快速开始
创建项目 : 在桌面建立一个文件夹 注: 不要取名webpack,可能会冲突
安装 webpack
安装的时候,不要使用 npm, 否则在 windows 上会失败。 请使用 cnpm
cnpm 是一个国内的镜像
执行
cnpm install -g webpack@1.13.2
如图所示安装结束后,运行
webpack
会看到很多的命令参数,其中,最开始的地方会看到版本 : webpack 1.13.2
main.js
在项目目录下创建 main.js.
这个js 很简单,就是输出一行 “hello webpack”
document.write("hello webpack");
使用 webpack 命令打包
webpack 输入路径 输出路径
在项目目录下运行 : 在当前路径,指定ES6 识别不了的文件, 然后指定打包后的文件
webpack a.js bundle.js
index.html
准备一个 index.html,运用使用这个 bundle.js 文件。bundle就是打包后的文件
<html>
<head>
<script src="bundle.js"></script>
</head>
</html>
打开 index.html
打开 index.html ,即可看到引用 bunlde.js 之后的效果。
如果对文章有疑问的地址建议 去 看看这篇文章 Npm的了解
命令行方式
webpack a.js bundle.js
如果文件名比较复杂,每一次敲入也是比较烦心的事情,所以可以采用配置文件的方式
module.exports = {
entry: './a.js',
output: {
filename: 'bundle.js'
}
};
运行
再次运行,就不需要使用 参数了,而是直接运行 webpack 命令就行了。 因为参数已经都放在 webpack.config.js 文件里面了
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190827193516782.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyODk3NDI3,size_16,color_FFFFFF,t_70
webpack-dev-server 是什么
在前面的例子里,是直接通过浏览器打开 index.html 的页面,这种情况与实际的项目是有区别的,因为实际项目通常都会是在一个服务器上打开 index.html.
webpack-dev-server 是什么呢? 它其实就是一个微服务器,运行它,也就启动了一个 web 服务器,可以方便地从服务器上打开这个 index.html 了
因为本系列教程里, webpack 是用 cnpm 安装的 1.32.2,考虑到兼容性, webpack-dev-server 也不会安装最新版本,而是与之兼容的版本: webpack-dev-server@1.15.0。
cnpm install -g webpack-dev-server@1.15.0
运行如下命令:
webpack-dev-server --open
会自动打开与 http 协议关联的浏览器,并显示默认的 index.html 页面。
http://localhost:8080/webpack-dev-server/
因为web 服务器总会默认访问 index.html页面,所以就看到了如图所示的效果
端口
默认访问的是8080端口,如果这个端口被占用了,那可以自定义其他端口。
修改 webpack.config.js 为如下代码。
然后重新运行
webpack-dev-derver --open
就会在如图所示的8088端口启动服务器了。
module.exports = {
entry: './a.js',
output: {
filename: 'bundle.js'
},
devServer: {
port:8088
}
}
热更新
webpack-dev-server 支持热更新。 所谓的热更新,即在 webpack.config.js 中的 entry 文件 ( a.js ) 发生了改变之后,会自动运行 webpack, 并且自动刷新页面,立即看到修改之后的效果。
为了做到这一点,需要修改 webpack.config.js 文件。
var webpack = require('webpack')
因为 webpack 模块是全局的,在某些情况下,通过这种方式导入不能够被识别,需要进行一次链接:
npm link webpack
然后把随后把 webpack.config.js 文件的内容更新如下代码所示。
var webpack = require('webpack')
module.exports = {
entry: './a.js',
output: {
filename: 'bundle.js'
},
plugins:[
new webpack.HotModuleReplacementPlugin()
],
devServer: {
port:8088,
inline:true,
hot:true
}
}
热更新测试
重新启动 webpack-dev-server
webpack-dev-server --open
随便改动一下 a.js 代码,会看到无需刷新 html 页面,自动看到最新的效果。
webpack 中 css 和 html 刷新问题的解决思路
点击查看
npm 启动方式
前面的方式,是直接运行 webpack-dev-server 的方式,不过大都数的项目,都会通过npm 的方式运行。
初始化
运行如下命令进行 package.json 配置文件的初始化
npm init -y
-y 的意思是都同意~ 就不用挨个挨个手动敲打回车了
package.json :
修改 package.json,增加脚本:
"dev": "webpack-dev-server --open"
{
"name": "webpack-demo",
"version": "1.0.0",
"main": "a.js",
"scripts": {
"dev": "webpack-dev-server --open"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"webpack": "^1.13.2"
},
"devDependencies": {},
"description": ""
}
运行
执行命令:
在scirpt 中是json 格式 (键值对)就相当于运行键
npm run dev
这样就和单独运行的效果是一样的了
测试
运行测试地址:
http://localhost:8088/
多个入口文件
有时候,会不止一个 js 文件,会有多个。 本知识点就是讲解这种情况下如何进行配置处理
a.js 修改 a.js 为如下代码
document.write("hello webpack from a.js<br>");
b.js
新增 b.js 为如下代码
document.write("hello webpack from b.js<br>");
webpack.config.json
修改配置文件为如下代码。 这回导致 a.js 被打包到 bundle1.js , b.js 被打包到 bundle2.js。
module.exports = {
entry: {
bundle1: './a.js',
bundle2: './b.js'
},
output: {
filename: '[name].js'
},
devServer: {
port:8088
}
}
修改 index.html
修改 index.html 为如下代码, 分别引用两个打包的文件。
<html>
<head>
<script src="bundle1.js"></script>
<script src="bundle2.js"></script>
</head>
</html>
运行测试
npm run dev
webpack Babel-loader
版本兼容问题
本教程建立在 cnpm 安装的如下webpack@1.13.2 和 webpack-dev-server@1.15.0 版本上,其他版本未经测试,不确保可用
cnpm install -g webpack@1.13.2
cnpm install -g webpack-dev-server@1.15.0
es6
ES6 的全称是 ECMAScript 6.0,是下一代的 javascript 语言标准。
因为当前 javascript 标准 (ES5) 对于开发大型的 javascritp 应用支持力度不足够,所以才会推出一个 ES6,期望 js 在大型企业开发领域也有所斩获。
如下代码所示,ES5 和 ES6 在语法上会有区别。
注: ES6 涉及的内容也是非常多的,在本文就不展开讲解了,以后有时间会专门做 ES6 的教程。
es5
var name = "ES5"
document.write(`hello `+ES5)
es6
const name = 'ES6'
document.write(`hello ${name}`)
babel
因为 ES6 标准推出时间还不够久,所以并不是所有的浏览器都支持 ES6 的运行。 因此,需要把 ES6 的 javascript 代码,转换为 ES5 标准的代码,以期能够在当下浏览器上兼容运行。
转换工具有很多种, babel 就是其中的一种。 本文就会讲解如何在 webpack 中使用 babel 工具来进行转换工作。
babel 安装
运行如下命令进行安装。 这些版本号都是经过站长测试,表示能够和当前 webpack@1.32.2 兼容的。
npm install --save-dev babel-loader@6.2.7 babel-core@6.18.0 babel-preset-latest@6.24.1
如果不加版本号。。。对不起,还真就用不起。。。 可见找这些能够匹配 webpack 的babel 版本,可真是累苦博主了
a.js
语法使用 ES6 的写法,这个是无法直接在 浏览器使用的,需要转换为 ES5 才能够使用。
const name = 'ES6'
document.write(`hello ${name}`)
package.config.js
修改 package.config.js:
- 入口重新设置为只有 a.js
- 出口是 bundle.js
- loaders 配置
3.1 表示仅仅转换 .js 文件
3.2 使用babel loader进行 es6 转换test: /.js$/,
3.3 latest 表示用最新的语法规则进行loader: 'babel',
query:{ presets: ['latest'] }
index.htmlmodule.exports = { entry: './a.js', output: { filename: 'bundle.js' }, devServer: { port:8088 }, module: { loaders: [ { test: /.js$/, loader: 'babel', query:{ presets: ['latest'] } } ] }
修改回来使用一个 bundle.js
<html>
<head>
<script src="bundle.js"></script>
</head>
</html>
运行 webpack
首先运行 webpack, 会把 a.js 转换为 bundle.js . 此时的 bundle.js 就是已经转换好了的。
打开 bundle.js 翻到最后几行,如图所示就已经是普通的 javascript 语句了。
运行
运行如下命令启动测试:
npm run dev
转换之后,能够识别 ES6。
如图所示
css 模块
在 webpack 的概念里,所有文件都是模块。 所以一个 css 文件也是模块。。。
本文讲解 如何用 css-loader 和 style-loader 把 css 文件作为一个模块打包到 bundle.js 文件里。 (没错。。。 样式也被搞到 js 文件里了。。。)
安装 css-loader 和 style-loader
首先通过如下命令安装 npm install style-loader css-loader --save-dev
npm install style-loader@0.13.1 css-loader@0.25.0 --save-dev
style.css
准备 style.css 文件,效果很简单,就是背景色变成蓝色
body {
background-color: blue;
}
package.config.js
修改 package.config.js,增加 style-loader 和 css-loader。 要使得css 起作用,得同时使用这两个 loader
module.exports = {
entry: './a.js',
output: {
filename: 'bundle.js'
},
devServer: {
port:8088
},
module: {
loaders: [
{
test: /.js$/,
loader: 'babel',
query:{
presets: ['latest']
}
},
{
test:/.css/,
loader:'style-loader!css-loader'
}
]
}
}
a.js
修改a.js ,把 style.css 当作一个模块加进来
require("./style.css")
require("./style.css")
const name = 'ES6'
document.write(`hello ${name}`)
运行
npm run dev