如果你的代码不需要模块化,那么你不需要 webpack;如果你的代码需要模块化,那么你可能需要 webpack;如果你的代码里,JavaScript、图片、CSS、JSON 等等千奇百怪的文件都要模块化,那么你一定需要 webpack。
为什么选择 webpack
webpack 官网 是这样定义 webpack 的:
webpack is a module bundler
什么是 module?我们首先会想到 JavaScript 的 ES 模块、AMD 模块,又或 Node.js 下的 CommonJS 模块。
只不过在 webpack 下,所有类型的文件都可以是模块,包括 JavaScript、CSS、图片、JSON。
我们当然知道在 JavaScript 里 import
/require
一张图片会报错。但在 webpack 下,这是允许的,这归功于加载器(loader)。通过加载器,webpack 将 JavaScript 的模块化推广到其它类型文件 - 这正是 webpack 跨出的与众不同的一步 - 但也导致它配置繁多,广受诟病。
但明白 webpack 这一用意,我们就掌握了 webpack 核心,接下来的事,查查文档基本都能搞定。
React.js 项目
我在这里草拟了一个简单的单页面应用,页面上有一张图片,点击图片,图片会旋转,再次点击则恢复原来的位置。
接下来我们将从零开始,用 webpack 搭建一个 React.js 开发环境,并完成编码、打包、部署。
初始化项目
首先,我们来初始化项目:
$ cd ~
$ mkdir -p tmp/webpack-demo && cd tmp/webpack-demo
$ npm init -y
项目初始化完成后,webpack-demo
目录下多出 package.json
文件,内容如下:
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
新建 HTML
在 webpack-demo
下新建 index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>webpack 教程</title>
</head>
<body>
</body>
</html>
我们暂时还没有引用 JavaScript。
创建 JavaScript 文件
在 webpack-demo
目录下新建 index.js
,内容暂时留空。
我们需要安装 react
及 react-dom
:
$ npm i react react-dom
装好后,在 index.js
文件中 import
它们:
import React from 'react'
import ReactDOM from 'react-dom'
好了,现在在 index.html
中引用 index.js
:
<body>
+ <script src="index.js"></script>
</body>
现在在浏览器中打开 index.html
,不出意外,console 中报错了,只是不同浏览器下报的错不一样:
- Firefox 59.0.2: SyntaxError: import declarations may only appear at top level of a module
- Safari 11.0.3: SyntaxError: Unexpected identifier 'React'. import call expects exactly one argument.
- Chrome 65.0.3325.181: Uncaught SyntaxError: Unexpected identifier
怎么办?浏览器的兼容性问题几乎是与生俱来的 - 要怎么抹平它们的差别,好让代码能够运行在尽可能多的浏览器平台上?
我们要用 webpack 来构建我们的源代码。
安装 webpack
在 webpack-demo
项目根目录中安装 webpack
:
$ npm install -D webpack
安装完成后,我们就会看到当前安装的 webpack 版本号。
编译 JavaScript
webpack 是个打包工具,那么就需要一个输入(入口文件),一个输出(目标文件)。
我们试试在命令行下将 index.js
打包成 build.min.js
:
$ npx webpack index.js -o build.min.js
The CLI moved into a separate package: webpack-cli
Would you like to install webpack-cli? (That will run npm install -D webpack-cli) (yes/NO)
没有打包,反而是提示我们是否安装 webpack-cli
。这是因为 webpack 在 webpack 4 里将命令行相关的都迁移至 webpack-cli
包。
输入 yes
然后回车,稍等一会儿,webpack-cli
就安装好了。之后我们的命令继续执行,结果如下:
Hash: cbb2732def750315c477
Version: webpack 4.5.0
Time: 243ms
Built at: 2018-4-7 09:56:02
Asset Size Chunks Chunk Names
build.min.js 105 KiB 0 [emitted] main
Entrypoint main = build.min.js
[13] ./index.js 58 bytes {0} [built]
+ 13 hidden modules
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
打包成功,但出现黄色警告。这是 webpack 4 引入的模式,包括 development
、production
、none
三个值,我们不传入值的话,默认使用 production
。
我们来调整下命令:
$ npx webpack index.js -o build.min.js --mode development
不再出现黄色警告了。
你可能好奇,不指定输入、输出的话会怎样?
我们来试试:
$ npx webpack --mode development
Hash: 86d52d22c7b7982a7ebf
Version: webpack 4.5.0
Time: 41ms
Built at: 2018-4-7 10:00:39
ERROR in Entry module not found: Error: Can't resolve './src' in '/Users/sam/tmp/webpack-demo'
报错,说在 ./src
下找不到 index.js
文件 - 这也是 webpack 4 引入的约定,不指定输入文件的话,则默认为 src/index.js
。我们按照约定将项目根目录下的 index.js
移动到 src/index.js
:
$ mkdir src
$ mv index.js src
然后再打包一遍:
$ npx webpack --mode development
Hash: 4726bc2e160759010056
Version: webpack 4.5.0
Time: 321ms
Built at: 2018-4-7 10:03:24
Asset Size Chunks Chunk Names
main.js 688 KiB main [emitted] main
Entrypoint main = main.js
[./src/index.js] 58 bytes {main} [built]
+ 21 hidden modules
打包成功,且目录下多出 dist/main.js
- 这也正是 webpack 4 未指定输出文件时默认的位置。也就是说,我们按照 webpack 约定组织代码文件的话,可以省去许多配置。
打包完成后,我们将 index.html
中对 JavaScript 引用调整为编译后的 dist/main.js
:
<body>
- <script src="./index.js"></script>
+ <script src="dist/main.js"></script>
</body>
再刷新浏览器,控制台已经不再报错。
但这样的代码结构在部署时十分不便,我们除了要拷贝 dist
目录外,还要从众多文件中拷贝出 index.html
文件,从部署上说,只需拷贝一个目录是最方便的,因此将 index.html
也移入 dist
目录,顺便清理 build.min.js
文件:
$ mv index.html dist
$ rm build.min.js
然后再调整 index.html
中的 js 引用:
<body>
- <script src="dist/main.js"></script>
+ <script src="main.js"></script>
</body>
实时刷新
在 index.html
文件中引用 main.js
文件后,我们有几个问题需要解决。
- 入口文件
src/index.js
的变化,包括它所引用的其它模块的变化如何通知给 webpack,以便重新构建dist/main.js
文件? dist/main.js
文件更新后,浏览器中打开的页面该如何自动刷新?
监控文件
第一个问题,webpack 有好几个解决办法,其中 watch
选项最直观,我们可以让 webpack
监控文件变化,一旦文件有变化,就重新构建。但默认情况下,watch
选项是禁用的。
我们可以在命令行下启用它:
$ npx webpack --mode development --watch
Webpack is watching the files…
Hash: 4726bc2e160759010056
Version: webpack 4.5.0
Time: 367ms
Built at: 2018-4-7 10:12:59
Asset Size Chunks Chunk Names
main.js 688 KiB main [emitted] main
Entrypoint main = main.js
[./src/index.js] 58 bytes {main} [built]
+ 21 hidden modules
我们试试在 index.js
文件中添加一行 console.log('hello webpack')
,保存文件后就会看到命令行下的变化:
Hash: 0d285ea4d1c26ac17380
Version: webpack 4.5.0
Time: 19ms
Built at: 2018-4-7 10:13:35
Asset Size Chunks Chunk Names
main.js 688 KiB main [emitted] main
Entrypoint main = main.js
[./src/index.js] 87 bytes {main} [built]
+ 21 hidden modules
webpack 监控到 src/index.js
文件的变化,重新构建了 dist/main.js
,耗时 19ms。
刷新浏览器
至于自动刷新浏览器的问题,webpack 提供 webpack-dev-server 来解决,它是一个基于 expressjs 的开发服务器,提供实时刷新浏览器页面的功能。不过目前 webpack-dev-server 已经进入维护模式,文档中推荐我们使用 webpack-serve
。
但这里暂时还是使用 webpack-dev-server
来说明。
webpack-dev-server
首先在项目下安装 webpack-dev-server
:
$ npm install -D webpack-dev-server
安装完成后在命令行下执行 webpack-dev-server
:
$ npx webpack-dev-server --mode development --content-base ./dist
ℹ 「wds」: Project is running at http://localhost:8080/
ℹ 「wds」: webpack output is served from /
ℹ 「wds」: Content not from webpack is served from /Users/sam/tmp/webpack-demo/dist
ℹ 「wdm」: Hash: 441c738298078bd7a80b
Version: webpack 4.5.0
Time: 508ms
Built at: 2018-4-13 19:52:45
Asset Size Chunks Chunk Names
main.js 1020 KiB main [emitted] main
Entrypoint main = main.js
[./node_modules/ansi-html/index.js] 4.16 KiB {main} [built]
[./node_modules/loglevel/lib/loglevel.js] 7.68 KiB {main} [built]
[./node_modules/react-dom/index.js] 1.33 KiB {main} [built]
[./node_modules/react/index.js] 190 bytes {main} [built]
[./node_modules/sockjs-client/dist/sockjs.js] 176 KiB {main} [built]
[./node_modules/url/url.js] 22.8 KiB {main} [built]
[./node_modules/webpack-dev-server/client/index.js?http://localhost:8080] (webpack)-dev-server/client?http://localhost:8080 7.75 KiB {main} [built]
[./node_modules/webpack-dev-server/client/overlay.js] (webpack)-dev-server/client/overlay.js 3.58 KiB {main} [built]
[./node_modules/webpack-dev-server/client/socket.js](webpack)-dev-server/client/socket.js 1.05 KiB {main} [built]
[./node_modules/webpack-dev-server/node_modules/strip-ansi/index.js] (webpack)-dev-server/node_modules/strip-ansi/index.js 161 bytes {main} [built]
[./node_modules/webpack/hot sync ^./log$] (webpack)/hot sync nonrecursive ^./log$ 170 bytes {main} [built]
[./node_modules/webpack/hot/emitter.js] (webpack)/hot/emitter.js 77 bytes {main} [built]
[0] multi (webpack)-dev-server/client?http://localhost:8080 ./src 40 bytes {main} [built]
[./node_modules/webpack/hot/log.js] (webpack)/hot/log.js 1.03 KiB {main} [optional] [built]
[./src/index.js] 87 bytes {main} [built]
+ 32 hidden modules
ℹ 「wdm」: Compiled successfully.
Ooops,令人晕眩的输出结果。
不过且忽视它们,我们现在可以在 http://localhost:8080/ 访问我们的 index.html
。
在入口文件 src/index.js
里再添加一行代码验证下浏览器页面的实时刷新功能:
console.log('webpack live reload is working')
webpack 重新打包了 dist/main.js
,浏览器中打开的页面同时也刷新了。实际上,我们看 webpack-dev-server 的命令行会发现,它同样监控入口文件的变化并重新编译 - 换句话说,webpack-dev-server
已经启用 --watch
效果。
编码
我们在 src/index.js
中先写个简单的 React 代码:
import React from 'react'
-import ReactDOM from 'react-dom'
+import ReactDOM from 'react-dom'
+ReactDOM.render(<div>hello webpack</div>, document.body)
注意,React 不推荐使用 body
上,这里只是图方便才这么写。
查看 webpack-dev-server 的状态:
[./src/index.js] 255 bytes {main} [built] [failed][1 error]
+ 25 hidden modules
ERROR in ./src/index.js
Module parse failed: Unexpected token (3:16)
You may need an appropriate loader to handle this file type.
| import React from 'react'
| import ReactDOM from 'react-dom'
| ReactDOM.render(<div>hello webpack</div>, document.body)
|
@ multi (webpack)-dev-server/client?http://localhost:8080 ./src
ℹ 「wdm」: Failed to compile.
报错。为什么?因为我们写了 JSX 语法,webpack 不认识。怎么办,找 babel-loader 来翻译。
$ npm install -D "babel-loader@^8.0.0-beta" @babel/core @babel/preset-react
接着重启 webpack-dev-server:
$ npx webpack-dev-server --mode development --content-base ./dist --module-bind 'js=babel-loader?presets[]=@babel/preset-react'
不再报错,且页面上已经显示 hello webpack
。
webpack 配置文件
随着我们配置的插件越来越多,命令行会越来越长,这时,我们可以将命令行参数移入 webpack 配置文件。
我们来新建一个 webpack.config.js
文件:
const path = require('path')
module.exports = {
mode: 'development',
devServer: {
contentBase: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /.js$/,
include: [
path.resolve(__dirname, 'src')
],
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react']
}
}
]
}
}
这样,我们只要执行 npx webpack-dev-server
就行,不再需要输入一长串命令行。
图片加载器
我们需要一张图片,我从 unsplash 找来了一张玫瑰,放到 src/img/rose.jpg
位置。
我们在 src/index.js
中 import
它:
import ReactDOM from 'react-dom'
+import Rose from './img/rose.jpg'
ReactDOM.render(<div>hello webpack</div>, document.body)
不出意外,报错了:
[./src/img/rose.jpg] 177 bytes {main} [built] [failed] [1 error]
[./src/index.js] 178 bytes {main} [built]
+ 46 hidden modules
ERROR in ./src/img/rose.jpg
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
@ ./src/index.js 3:0-34
@ multi (webpack)-dev-server/client?http://localhost:8080 ./src
ℹ 「wdm」: Failed to compile.
和处理 JSX 一个道理,我们需要翻译(即加载器)。
在 webpack 里,负责图片翻译的是 file-loader:
$ npm install -D file-loader
接着是配置 webpack.config.js
:
+ },
+ {
+ test: /.(png|jpg|gif)$/,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {}
+ }
+ ]
}
]
重启 webpack-dev-server,发现 webpack 已经能正常编译了 - 图片摇身一变,也是一个模块。
而且,webpack 在最终构建时,会自动将模块中引用的图片拷贝到相应目录 - 谢天谢地,再也不用手动拷贝。
确保图片加载没问题后,我们来完善下代码:
-ReactDOM.render(<div>hello webpack</div>, document.body)
+class App extends React.Component {
+ render () {
+ return (
+ <div><img src={Rose} alt='玫瑰' /></div>
+ )
+ }
+}
+ReactDOM.render(<App />, document.body)
查看浏览器,图片已经渲染出来 - 但是图片太大了。我们需要 CSS 来控制图片尺寸。
加载 CSS 文件
在 React.js 里,CSS 有很多种写法,比如我们可以直接写在 style
中:
<img src={Rose} alt='玫瑰' style={{maxWidth: 500}} />
因为这就是 JavaScript,我们也就不需要额外处理。
但我们也可以写在 css 文件中。
在 src
下新增 index.css
:
.flower {
max-width: 500px;
}
然后在 index.js
中引入并应用:
import React from 'react'
import ReactDOM from 'react-dom'
import Rose from './img/rose.jpg'
+import './index.css'
class App extends React.Component {
render () {
return (
- <div><img src={Rose} alt='玫瑰' /></div>
+ <div><img src={Rose} alt='玫瑰' className='flower' /></div>
)
}
}
但 webpack-dev-server 又报错了:
[./src/index.css] 166 bytes {main} [built] [failed] [1 error]
[./src/index.js] 391 bytes {main} [built]
+ 47 hidden modules
ERROR in ./src/index.css
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| .flower {
| max- 500px;
| }
@ ./src/index.js 4:0-21
@ multi (webpack)-dev-server/client?http://localhost:8080 ./src
ℹ 「wdm」: Failed to compile.
同样的,我们需要 CSS 加载器:
- css-loader - 预处理 CSS 文件
- style-loader - 将 CSS 插入到 DOM 中的
style
标签
注意,我们如果只使用了 css-loader,则 webpack 只是将 CSS 文件预处理成模块然后打包到构建文件中,并不会插入到页面 - 这是 style-loader
的作用。
我们先来安装它们:
$ npm install -D css-loader style-loader
然后修改 webpack.config.js
配置:
+ },
+ {
+ test: /.css$/,
+ use: [{ loader: 'style-loader' }, { loader: 'css-loader' }]
}
]
}
请注意,loader 的顺序很重要,比如上面新增的这一节,如果把 style-loader
放到 css-loader
后面,我们就会撞见错误:
ERROR in ./index.css
Module build failed: Unknown word (5:1)
3 | // load the styles
4 | var content = require("!!./index.css");
> 5 | if(typeof content === 'string') content = [[module.id, content, '']];
| ^
6 | // Prepare cssTransformation
7 | var transform;
8 |
@ ./index.js 3:0-21
@ multi (webpack)-dev-server/client?http://localhost:8080 ./index.js
webpack: Failed to compile
因为 style-loader
无法理解 CSS 文件,需要先经 css-loader
预处理 - 是的,加载器的执行顺序是从后往前的。
重启 webpack-dev-server,编译正常,css 已生效。
只不过,这里的 CSS 虽然是 import
进来的,但仍是全局的,等效于我们平常使用 <link href="" />
引用 CSS。webpack 还提供 CSS Modules,可以将样式真正意义上的模块化。
除了 CSS Modules 外,我们还有很多 CSS in js 方案可选,它们允许我们将样式跟 HTML、JS 放到一起 - 如果你写过 Vue.js 的单文件模块,可能会很喜欢。
在成功配置图片与 CSS 后,我们可以继续完善代码:
src/index.css
:
+}
+.flower--rotate {
+ transform: rotate(30deg);
}
src/index.js
:
class App extends React.Component {
+ state = {
+ reset: 'yes'
+ }
+ onClick = () => {
+ this.setState({
+ reset: this.state.reset === 'yes' ? 'no' : 'yes'
+ })
+ }
render () {
return (
- <div><img src={Rose} alt='玫瑰' className='flower' /></div>
+ <div><img src={Rose} alt='玫瑰' className={this.state.reset === 'yes' ? 'flower' : 'flower flower--rotate'} onClick={this.onClick} /></div>
)
}
}
但随即发现 webpack-dev-server 又抛出错误:
[./src/index.js] 1.49 KiB {main} [built] [failed] [1 error]
+ 25 hidden modules
ERROR in ./src/index.js
Module build failed: SyntaxError: /Users/sam/tmp/webpack-demo/src/index.js: Support for the experimental syntax 'classProperties' isn't currently enabled (6:9):
4 | import './index.css'
5 | class App extends React.Component {
> 6 | state = {
| ^
7 | reset: 'yes'
8 | }
9 | onClick = () => {
Add @babel/plugin-proposal-class-properties (https://git.io/vb4SL) to the 'plugins' section of your Babel config to enable transformation.
at _class.raise (/Users/sam/tmp/webpack-demo/node_modules/babylon/lib/index.js:779:15)
at _class.expectPlugin (/Users/sam/tmp/webpack-demo/node_modules/babylon/lib/index.js:2087:18)
at _class.parseClassProperty (/Users/sam/tmp/webpack-demo/node_modules/babylon/lib/index.js:4904:12)
at _class.pushClassProperty (/Users/sam/tmp/webpack-demo/node_modules/babylon/lib/index.js:4871:30)
at _class.parseClassMemberWithIsStatic (/Users/sam/tmp/webpack-demo/node_modules/babylon/lib/index.js:4804:14)
at _class.parseClassMember (/Users/sam/tmp/webpack-demo/node_modules/babylon/lib/index.js:4741:10)
at _class.parseClassBody (/Users/sam/tmp/webpack-demo/node_modules/babylon/lib/index.js:4696:12)
at _class.parseClass (/Users/sam/tmp/webpack-demo/node_modules/babylon/lib/index.js:4646:10)
at _class.parseStatementContent (/Users/sam/tmp/webpack-demo/node_modules/babylon/lib/index.js:3987:21)
at _class.parseStatement (/Users/sam/tmp/webpack-demo/node_modules/babylon/lib/index.js:3959:17)
@ multi (webpack)-dev-server/client?http://localhost:8080 ./src
ℹ 「wdm」: Failed to compile.
这是因为我们用了 JavaScript 的新特性 - 需要 @babel/plugin-proposal-class-properties
插件的支持。
首先是安装该插件:
$ npm i -D @babel/plugin-proposal-class-properties
然后调整 webpack.config.js
配置:
options: {
presets: ['@babel/preset-react']
+ plugins: ['@babel/plugin-proposal-class-properties']
}
},
重启 webpack-dev-server,编译正常。
查看浏览器,图片已经可以点击了。
打包
在完成项目开发后,我们需要输出文件给生产环境部署,只要执行:
$ npx webpack --mode production
就可以打包出所有静态资源。
部署
部署时,拷贝 dist
目录即可。
清理 dist
随着某些文件的增删,我们的 dist
目录下会产生一些不再使用的文件,我们不想这些文件也部署到生产环境上占用空间,所以 webpack 在打包前最好能删除 dist
目录。
我们来试试 clean-webpack-plugin。
首先是安装:
$ npm i -D clean-webpack-plugin
然后在 webpack.config.js
中调用:
const path = require('path')
+const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
mode: 'development',
devServer: {
contentBase: path.resolve(__dirname, 'dist')
},
+ plugins: [
+ new CleanWebpackPlugin(['dist'])
+ ],
module: {
再执行 npx webpack --mode production
,webpack 确实会在打包前清空 dist
目录,但我们的 index.html
也一起被清空了。
html-webpack-plugin
我们使用 html-webpack-plugin 来自动生成 index.html
。
首先是安装:
$ npm i --save-dev html-webpack-plugin
调整 webpack.config.js
:
const CleanWebpackPlugin = require('clean-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
devServer: {
contentBase: path.resolve(__dirname, 'dist')
},
plugins: [
- new CleanWebpackPlugin(['dist'])
+ new CleanWebpackPlugin(['dist']),
+ new HtmlWebpackPlugin()
],
再运行 npx webpack --mode production
,dist
下已经自动生成 index.html
,再 title 却是 Webpack App
,我们需要再调整一下 webpack.config.js
:
plugins: [
new CleanWebpackPlugin(['dist']),
- new HtmlWebpackPlugin()
+ new HtmlWebpackPlugin({
+ title: 'webpack 教程'
+ })
],
脚手架
前面的步骤里,我们几乎是一步、一步手动配置每个类型文件的加载器,一次添加一小节,然后重启 webpack-dev-server
,恐怕没人喜欢这样干活。所以市面上有非常多的 boilerplates、presets 等,其中比较出名的有:
- create-react-app react 官方出品的一套,只适用开发 react.js 项目;
- neutrino.js 这是 Mozilla 出品的一套解决方案,Web、React、Node.js 等方案均有;
- Parcel 最近新出的一套方案,零配置。
博主在这里就不详细介绍webpack来源以及作用了, 本篇博文面向新手主要说明如何配置webpack, 以及webpack的使用方法, 直到创建出一个合理的属于自己webpack项目;
流程
webpack安装
Step 1: 首先安装Node.js, 可以去Node.js官网下载.
Step2: 在Git或者cmd中输入下面这段代码, 通过全局先将webpack指令安装进电脑中
npm install webpack -g
- Step3: 使用Git Bash here 或者 cmd cd命令使当前目录转到当前项目的目录下, 然后输入下面这段命令
npm init
接下来会弹出一些信息, 就是一些项目名和一些参数的描述, 可以全部按回车使用默认信息, 完成之后项目文件夹下会生成一个package.json的文件
这样webpack就安装完成了.
webpack配置
- Step1: 创建项目文件夹, 名字自起, 但路径名不要包含中文, 以及项目名也不要叫”webpack”, 并且不要包含大写字母.
例: - Step2: 接下来创建并编写配置文件. 首先我们先介绍几个配置文件的参数.
- entry: 是 页面入口文件配置 (html文件引入唯一的js 文件)
- output:对应输出项配置
- path :入口文件最终要输出到哪里,
- filename:输出文件的名称
- publicPath:公共资源路径
- Step3: 在你的项目目录下创建webpack.config.js配置文件, 通过这个文件进行webpack的配置, 并且还要创建一些路径保存基本文件. 例如:
src文件夹 Step4: 在src的js下创建一个入口文件, 我创建的叫做entry.js, 在项目目录再创建一个index.html用来调试使用. 编写webpack.config.js文件,
//webpack.config.js module.exports = { entry : './src/js/entry.js',//入口文件 output : {//输出文件 filename : 'index.js',//输出文件名 path : __dirname + '/out'//输出文件路径 }, }
- 我们随便在index.html和入口文件entry.js写点什么看看是否成功配置,
//index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>ss</title> </head> <body> 111 <script src="./out/index.js"></script>//注意在这里引入的是打包完成的js文件 </body> </html>
//entry.js console.log('1234');
之后使用Git Bash here 或者 cmd cd命令使目录为当前项目目录, 输入webpack或者webpack -w命令, 查看index.html是否成功console出1234;
webpack 和 webpack -w 区别
webpack -w可以对项目打包并且实时监控, 当前配置文件下的文件如果发生更改时重新打包, 但如果webpack的配置文件即webpack.config.js更改时还是要通过webpack进行打包.(退出webpack -w 操作 ctrl+c)
webpack loader加载器
接下来我们继续配置loader, 通过加载器处理文件:比如 sass less 等, 告知 webpack 每一种文件都需要使用什么加载器来处理。
Step1: 为了方便我们先统一把所有的包都先下载下来, 下面再慢慢解释.
npm install babel-loader babel babel-core css-loader style-loader url-loader file-loader less-loader less --save-dev
Step2: 下载完成后, 我们修改webpack.config.js文件, 将加载器引入.
module.exports = { entry : './src/js/entry.js', output : { filename : 'index.js', path : __dirname + '/out' }, module : { rules: [ {test: /.js$/, use: ['babel-loader']}, {test: /.css$/, use: ['style-loader', 'css-loader']},/*解析css, 并把css添加到html的style标签里*/ //{test: /.css$/, use: ExtractTextPlugin.extract({fallback: 'style-loader',use: 'css-loader'})},/*解析css, 并把css变成文件通过link标签引入*/ {test: /.(jpg|png|gif|svg)$/, use: ['url-loader?limit=8192&name=./[name].[ext]']},/*解析图片*/ {test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader']}/*解析less, 把less解析成浏览器可以识别的css语言*/ ] }, }
Step3: 接下来我们先测试css, 我们在项目文件夹下的src文件夹下创建index.css. 随便写一点属性.
//index.css .demo1 { width: 100px; height: 100px; background: red; } .demo2 { width: 200px; height: 200px; background: orange; }
//index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>text</title> </head> <body> <div class="demo1"></div> <div class="demo2"></div> <script src="./out/index.js"></script> </body> </html>
因为在webpack中所有文件都是模块, 所以必须要将css引入. 在刚刚的entry.js中添加如下代码.
//entry.js require('../css/index.css');//引入css文件 console.log("1234");
打包webpack一下看看效果
Step4: 当有多个js文件时, 如何进行引入呢? 接下来我们做一个简单小功能来说明这个问题, 让我们点击方块的时候, 方块变大.
接下来在src的js文件夹下创建一个基本的工具tool.js (很多小的问题都被我扩大化了, 只是为了说明问题不一定适用)
//tool.js var tool = {//获取DOM元素 getDom: function(className) { return document.getElementsByClassName(className)[0]; } } module.exports = tool;//模块出口
src的js下创建一个demo1.js文件, demo2.js同理
var obj = require('./tool.js'); var demo1 = { init: function() { this.bindEvent(); }, bindEvent: function() { //var demo1 = document.getElementsByClassName('demo1')[0]; var demo1 = obj.getDom('demo1'); demo1.onclick = this.changeStyle; }, changeStyle: function() { this.style.width = '200px'; this.style.height = '200px'; this.style.background = 'green'; console.log('1'); } } module.exports = demo1;
修改入口文件entry.js
require('../css/index.css'); var demo1 = require('../js/demo1.js'); var demo2 = require('../js/demo2.js'); demo1.init(); demo2.init();
webpack一下, 看看效果
关于图片的打包
- Step1: 在img文件夹下随便找一个小一点的图片放进去.
Step2: 修改entry.js
require('../css/index.css'); var demo1 = require('../js/demo1.js'); var demo2 = require('../js/demo2.js'); demo1.init(); demo2.init(); var oImg = new Image(); oImg.src = require('../img/1.gif');//当成模块引入图片 document.body.appendChild(oImg);
由于我们引入的是静态资源, 在webpack.config.js中修改一下
module.exports = { entry : './src/js/entry.js', output : { filename : 'index.js', publicPath: __dirname + '/out',//添加静态资源, 否则会出现路径错误 path : __dirname + '/out' }, module : { rules: [ {test: /.js$/, use: ['babel-loader']}, {test: /.css$/, use: ['style-loader', 'css-loader']},/*解析css, 并把css添加到html的style标签里*/ //{test: /.css$/, use: ExtractTextPlugin.extract({fallback: 'style-loader',use: 'css-loader'})},/*解析css, 并把css变成文件通过link标签引入*/ {test: /.(jpg|png|gif|svg)$/, use: ['url-loader?limit=8192&name=./[name].[ext]']},/*解析图片*/ {test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader']}/*解析less, 把less解析成浏览器可以识别的css语言*/ ] }, }
大家自己webpack看看效果
webpack进阶设定
我们在项目中有多个html文件时怎么处理呢?, 接下来我们重新设定配置文件, webpack.config.js
module.exports = {
entry : {index1: './src/js/entry.js', index2: './src/js/entry2.js'},
output : {
filename : '[name].js',//这样就可以生成两个js文件, 名字分别为index1.js, 和index2.js
publicPath: __dirname + '/out',//添加静态资源, 否则会出现路径错误
path : __dirname + '/out'
},
module : {
rules: [
{test: /.js$/, use: ['babel-loader']},
{test: /.css$/, use: ['style-loader', 'css-loader']},/*解析css, 并把css添加到html的style标签里*/
//{test: /.css$/, use: ExtractTextPlugin.extract({fallback: 'style-loader',use: 'css-loader'})},/*解析css, 并把css变成文件通过link标签引入*/
{test: /.(jpg|png|gif|svg)$/, use: ['url-loader?limit=8192&name=./[name].[ext]']},/*解析图片*/
{test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader']}/*解析less, 把less解析成浏览器可以识别的css语言*/
]
},
}
webpack插件使用
首先我们由于要使用webpack插件, 因此我们要重新下载一下webpack包, 将目录定位到当前项目目录, 输入npm install webpack
之后我们修改webpack.config.js, 将下面代码放到配置文件开头. 这样就可以使用插件了
var webpack = require('webpack');
- 1
将插件信息写到配置文件里
var webpack = require('webpack');
var uglifyPlugin = new webpack.optimize.UglifyJsPlugin({minimize: true});//代码压缩
var CommonsChunkPlugin = new webpack.optimize.CommonsChunkPlugin('common');//把公共模块提取出来, 并取名为'common'(名字自起), webpack之后再out文件夹下生成common.js, 测试时记得引入提取出来的公共模块js文件
var ExtractTextPlugin = require("extract-text-webpack-plugin");//将css独立引入变成link标签形式, 使用该插件需要独立下载'npm install extract-text-webpack-plugin --save-dev', 同时下面的rules也必须更改
var providePlugin = new webpack.ProvidePlugin({$: 'jquery', jQuery: 'jquery', 'window.jQuery': 'jquery'});//引入jquery
module.exports = {
entry : {index: './src/js/entry.js', index2: './src/js/entry2.js'},
output : {
filename : '[name].js',
publicPath: __dirname + '/out',
path : __dirname + '/out'
},
module : {
rules: [
{test: /.js$/, use: ['babel-loader']},
//{test: /.css$/, use: ['style-loader', 'css-loader']},
{test: /.css$/, use: ExtractTextPlugin.extract({fallback: 'style-loader',use: 'css-loader'})},
{test: /.(jpg|png|gif|svg)$/, use: ['url-loader?limit=8192&name=./[name].[ext]']},
{test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader']}
]
},
plugins: [uglifyPlugin, CommonsChunkPlugin, new ExtractTextPlugin('[name].css'),providePlugin]//插件集合
}
webpack服务器
首先先定位目录输入命令 npm install webpack-dev-server -g
, 修改webpack.config.js文件
publicPath: 'http://localhost:8080/out',
- 1
html文件所引用的目录也要更改:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>text</title>
<link rel="stylesheet" href="http://localhost:8080/out/index.css">
</head>
<body>
<a href="http://localhost:8080/index2.html">11</a>
<div class="demo1"></div>
<div class="demo2"></div>
<script src="http://localhost:8080/out/common.js"></script>
<script src="http://localhost:8080/out/index.js"></script>
</body>
</html>
- webpack-dev-server一下看看效果
小工具: webpace-dev-server –devtool eval-source-map –progess –colors打包时输入这一行可以直接找到文件如果出错时的位置
小知识点: 上面这一句话如果觉得太长可以将
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"xuan": "webpack-dev-server --devtool eval-source-map --progress --colors"
},
这一段代码放到项目目录下的package.json里, 这样调试时如果输入npm run xuan就等于输入那一长串代码