|
| 1 | +# webpack |
| 2 | + |
| 3 | +基于 NodeJS 的一个著名第三方模块,主要目的是来实现前端模块化和自动化的,在这之前还有一个跟它类似的 gulp ,也是一个自动化构建工具,主要功能是打包合并压缩重命名等... |
| 4 | + |
| 5 | +webpack 其实也是一套自动化构建工具,在打包代码的时候也是跟 gulp 很相似的 |
| 6 | + |
| 7 | +<img src="what-is-webpack.png" /> |
| 8 | + |
| 9 | +左边比较多的文件(模块),也比较多的格式(js,css,html,jsx,scss),右边文件比较少,大部分都是转为JS格式,还有一些图片格式,所以 webpack 其实处理各种类型的文件,最终想把他们尽可能的转为JS类型的文件(打包,合并,压缩),webpack 多变少(或一个),多文件进少文件或者单文件出,而 gulp 更多的是多文件变相同多的文件,多进多出 |
| 10 | + |
| 11 | +一般开发目录是在`entry`里面,发布是在`output`文件夹 |
| 12 | + |
| 13 | +## 安装 |
| 14 | + |
| 15 | + |
| 16 | +1. 在根目录下新建`webpack.config.js` |
| 17 | +```js |
| 18 | +gulp gulpfile.js |
| 19 | +webpack webpack.config.js |
| 20 | +``` |
| 21 | +2. 用npm安装`webpack`的依赖包,全局安装一次,本地也安装一次 |
| 22 | + |
| 23 | +```bash |
| 24 | +npm install gulp -g //全局 |
| 25 | +npm install gulp //本地 |
| 26 | + |
| 27 | + |
| 28 | +npm install webpack -g |
| 29 | +npm install webpack-cli -g |
| 30 | +npm install webpack |
| 31 | +``` |
| 32 | + |
| 33 | +3. 往配置文件里面写对应的配置 |
| 34 | + |
| 35 | +四大概念 |
| 36 | +1. 入口(entry) |
| 37 | +2. 输出(output) |
| 38 | +3. loader |
| 39 | +4. 插件(plugins) |
| 40 | + |
| 41 | +## entry |
| 42 | + |
| 43 | +跟我们的`gulp`的`gulp.src()`,入口其实就是要导入需要处理的文件,放文件名 |
| 44 | + |
| 45 | +在`webpack.config.js`同级目录下,新建`entry`文件夹 |
| 46 | +```js |
| 47 | +// 配置参数 |
| 48 | +module.exports = { |
| 49 | + // 入口 把index.js导入进来处理 |
| 50 | + entry: './entry/index.js' |
| 51 | +}; |
| 52 | +``` |
| 53 | + |
| 54 | +## output |
| 55 | + |
| 56 | +在`webpack.config.js`同级目录下,新建`output`文件夹 |
| 57 | +```js |
| 58 | +const path = require('path'); |
| 59 | +// 配置参数 |
| 60 | +module.exports = { |
| 61 | + // 入口 把index.js导入进来处理 |
| 62 | + entry: './entry/index.js', |
| 63 | + output: { |
| 64 | + // 写一段路径,寻找output文件夹 |
| 65 | + path: path.resolve(__dirname, 'output'), |
| 66 | + // 在output文件夹里面导出文件名为bundle.js |
| 67 | + filename: 'bundle.js' |
| 68 | + } |
| 69 | +}; |
| 70 | +``` |
| 71 | + |
| 72 | +在入口文件夹`entry`的`index.js`里面写入以下代码 |
| 73 | +```js |
| 74 | +import $ from "jquery";//记得先安装 npm install jquery |
| 75 | +$("body").html("helloworld"); |
| 76 | +``` |
| 77 | + |
| 78 | +4. 编译 |
| 79 | + |
| 80 | +在`webpack.config.js`文件夹的命令行里面执行`webpack`命令,如果成功的话会在`output`文件夹下生成一份新的`bundle.js` |
| 81 | +```js |
| 82 | +webpack |
| 83 | +``` |
| 84 | +`require.js`模块化,分开模块管理项目,并且能重复使用模块 |
| 85 | + |
| 86 | +> webpack = gulp + requirejs |
| 87 | +
|
| 88 | +既做打包合并也做模块化,相对于`gulp`,它就是更偏重于模块化 |
| 89 | + |
| 90 | +`vue-cli`基于`webpack`,它就的模块化就是基于webpack的 |
| 91 | + |
| 92 | + |
| 93 | +## loader |
| 94 | + |
| 95 | +webpack 它默认只能处理JS类型文件,它不自带处理其他非JS文件的功能,如果你想 webpack 处理非 JS 类型文件,必须安装其他第三方插件来实现,webpack 里面这种插件称之为`loaders`(加载器) |
| 96 | + |
| 97 | +> loader = 处理各种非JS类型文件 |
| 98 | +
|
| 99 | +这个功能类似于 gulp 的拓展功能,需要装第三方插件 |
| 100 | +```bash |
| 101 | +gulp-sass |
| 102 | +gulp-minify |
| 103 | +gulp-concat |
| 104 | +``` |
| 105 | +比如`.vue`组件是非JS类型文件,我们就需要安装`vue-loader`来处理,类似的还有以下这些 |
| 106 | +```bash |
| 107 | +npm install vue-loader |
| 108 | +npm install sass-loader |
| 109 | +npm install html-loader |
| 110 | +npm install css-loader |
| 111 | +npm install json-loader |
| 112 | +``` |
| 113 | +安装完对应的loader之后,还需要在`webpack.config.js`文件里面进行配置 |
| 114 | + |
| 115 | +这些loader都是帮你处理不同类型的文件(非JS类型文件),`test`是正则,匹配文件名字,`use`是加上你对应`loader`的名字 |
| 116 | + |
| 117 | +```js |
| 118 | +module: { |
| 119 | + rules: [{ |
| 120 | + test: /\.vue$/, |
| 121 | + use: 'vue-loader' |
| 122 | + }, { |
| 123 | + test: /\.css$/, |
| 124 | + use: ['style-loader', 'css-loader'] |
| 125 | + }, { |
| 126 | + test: /\.png|jpg|jpeg$/, |
| 127 | + use: ['url-loader'] |
| 128 | + }] |
| 129 | +}, |
| 130 | +``` |
| 131 | + |
| 132 | + |
| 133 | +# React项目结构 |
| 134 | +```json |
| 135 | +--your project |
| 136 | + |--app |
| 137 | + |--components |
| 138 | + |--productBox.jsx |
| 139 | + |--main.js |
| 140 | + |--build |
| 141 | + |--index.html |
| 142 | + |--bundle.js(该文件是webpack打包后生成的) |
| 143 | +``` |
| 144 | + |
| 145 | +## 用npm安装react、webpack |
| 146 | +默认已经安装了[NodeJS](https://nodejs.org/en/),推荐用`cnpm` |
| 147 | +```bash |
| 148 | +npm install --save-dev react react-dom --save-dev |
| 149 | +npm install -g webpack --save-dev//建议webpack全局安装,方便我们后面使用webpack命令 |
| 150 | +``` |
| 151 | + |
| 152 | + |
| 153 | +## 安装和配置Babel |
| 154 | +Babel其实是一个编译JavaScript的平台,它的强大之处表现在可以通过编译帮你达到以下目的: |
| 155 | + |
| 156 | +> 下一代的JavaScript标准(ES6,ES7),这些标准目前并未被当前的浏览器完全的支持; |
| 157 | +> 使用基于JavaScript进行了拓展的语言,比如React的JSX |
| 158 | +> Babel其实是几个模块化的包,其核心功能位于称为babel-core的npm包中,不过webpack把它们整合在一起使用,但是对于每一个你需要的功能或拓展,你都需要安装单独的包(用得最多的是解析Es6的babel-preset-es2015包和解析JSX的babel-preset-react包)。 |
| 159 | +``` |
| 160 | +npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react |
| 161 | +``` |
| 162 | +在项目根目录下新建`.babelrc`文件,就是只有后缀名的文件,添加如下代码 |
| 163 | +```json |
| 164 | +//.babelrc |
| 165 | +{ |
| 166 | + "presets": [ |
| 167 | + "react", |
| 168 | + "es2015" |
| 169 | + ] |
| 170 | +} |
| 171 | +``` |
| 172 | + |
| 173 | +## 安装其他loader |
| 174 | +讲到这里,我们基本上就可以迅速搭建一个简单的web项目,但不得不提的是webpack loader。它是我个人认为相比于其他模块加载更牛X的地方,将它用于react的开发,结合react与生俱来的优越性能,两者天衣无缝的配合简直就是黄金组合。 |
| 175 | + |
| 176 | +总的来说 webpack 的 loader可以实现: |
| 177 | + |
| 178 | +> 可以将React JSX语法转为js语句 |
| 179 | +> React开发中支持ES6语法 |
| 180 | +> 支持通过import来直接引入css、less、sass甚至是图片 |
| 181 | +> 支持css中引用的图片大小在某一大小范围之内直接转为BASE64格式等等等 |
| 182 | +
|
| 183 | +为了能够让以上功能奏效,我们要先安装对应的: |
| 184 | +babel-loader |
| 185 | +```bash |
| 186 | +npm install babel-loader --save-dev |
| 187 | +//css-loader |
| 188 | +npm install css-loader --save-dev |
| 189 | +//less-loader |
| 190 | +npm install less-loader --save-dev |
| 191 | +//style-loader |
| 192 | +npm install style-loader --save-dev |
| 193 | +//url-loader |
| 194 | +npm install url-loader --save-dev |
| 195 | +``` |
| 196 | +而具体的实现,我们只要在下面webpack的配置文件中加入module属性里的loaders: |
| 197 | + |
| 198 | +## 配置webpack.config.js |
| 199 | +webpack.config.js 是 webpack 的配置文件 |
| 200 | +```js |
| 201 | +//__dirname是node.js中的一个全局变量,它指向当前执行脚本所在的目录 |
| 202 | +module.exports = { //注意这里是exports不是export |
| 203 | + devtool: 'eval-source-map', //生成Source Maps,这里选择eval-source-map |
| 204 | + entry: __dirname + "/app/main.js", //唯一入口文件 |
| 205 | + output: { //输出目录 |
| 206 | + path: __dirname + "/build", //打包后的js文件存放的地方 |
| 207 | + filename: 'bundle.js', //打包后的js文件名 |
| 208 | + }, |
| 209 | + module: { |
| 210 | + loaders: [{ |
| 211 | + test: /\.jsx?$/, |
| 212 | + exclude: /node_modules/, //屏蔽不需要处理的文件(文件夹)(可选) |
| 213 | + loader: 'babel-loader' |
| 214 | + //npm install babel-loader |
| 215 | + //npm install babel-core |
| 216 | + }, { |
| 217 | + test: /\.css$/, |
| 218 | + loader: 'style-loader!css-loader' |
| 219 | + }, { |
| 220 | + test: /\.less$/, |
| 221 | + loader: 'style-loader!css-loader!less-loader' |
| 222 | + }, { |
| 223 | + test: /\.(png|jpg)$/, |
| 224 | + loader: 'url-loader?limit=25000' |
| 225 | + }] |
| 226 | + } |
| 227 | +}; |
| 228 | +``` |
| 229 | +使用 Source Maps,使调试更容易 |
| 230 | + |
| 231 | +|devtool选项|配置结果| |
| 232 | +|-|-| |
| 233 | +|source-map|在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包文件的构建速度| |
| 234 | +|cheap-module-source-map|在一个单独的文件中生成一个不带列映射的map,不带列映射提高项目构建速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便| |
| 235 | +|eval-source-map|使用eval打包源文件模块,在同一个文件中生成干净的完整的source map。这个选项可以在不影响构建速度的前提下生成完整的sourcemap,但是对打包后输出的JS文件的执行具有性能和安全的隐患。不过在开发阶段这是一个非常好的选项,但是在生产阶段一定不要用这个选项| |
| 236 | +|cheap-module-eval-source-map|这是在打包文件时最快的生成source map的方法,生成的Source Map 会和打包后的JavaScript文件同行显示,没有列映射,和eval-source-map选项具有相似的缺点| |
| 237 | + |
| 238 | +## 组件productBox.jsx |
| 239 | +新版本推荐使用ES6书写React组件 |
| 240 | +```js |
| 241 | +var React = require('react'); |
| 242 | +//旧版本的写法,会有警告 |
| 243 | +/*var ProductBox = React.createClass({ |
| 244 | + render: function() { |
| 245 | + return( |
| 246 | + <div className = "productBox" > |
| 247 | + Hello World! |
| 248 | + </div> |
| 249 | + ); |
| 250 | + } |
| 251 | +});*/ |
| 252 | +//新版本的写法 推荐 |
| 253 | +class ProductBox extends React.Component { |
| 254 | + render() { |
| 255 | + return( |
| 256 | + <div>Hello World!</div> |
| 257 | + ) |
| 258 | + } |
| 259 | +} |
| 260 | +module.exports = ProductBox; |
| 261 | +``` |
| 262 | +用旧版本写法会出现以下警告 |
| 263 | + |
| 264 | + |
| 265 | +## 前端页面index.html |
| 266 | +index.html是最终要呈现的页面文件,代码如下 |
| 267 | +```html |
| 268 | +<!DOCTYPE html> |
| 269 | +<html> |
| 270 | + <head lang="en"> |
| 271 | + <meta charset="UTF-8"> |
| 272 | + <title>React Test</title> |
| 273 | + </head> |
| 274 | + <body> |
| 275 | + <!--要插入React组件的位置--> |
| 276 | + <div id="content"></div> |
| 277 | + <script src="bundle.js"></script> |
| 278 | + </body |
| 279 | +</html> |
| 280 | +``` |
| 281 | + |
| 282 | +## 入口文件main.js |
| 283 | +main.js是入口文件,用来将React组件放在真正的html中 |
| 284 | +```js |
| 285 | +var React = require('react'); |
| 286 | +var ReactDom = require('react-dom'); |
| 287 | +var AppComponent = require('./components/productBox.jsx'); |
| 288 | +ReactDom.render( |
| 289 | + <AppComponent / > |
| 290 | + , document.getElementById('content') |
| 291 | +); |
| 292 | +``` |
| 293 | + |
| 294 | +## 依赖的描述文件package.json |
| 295 | + |
| 296 | +package.json是一个标准的npm说明文件,里面蕴含了丰富的信息,包括当前项目的依赖模块,自定义的脚本任务等 |
| 297 | +```json |
| 298 | +{ |
| 299 | + "devDependencies": { |
| 300 | + "babel-core": "^6.24.1", |
| 301 | + "babel-loader": "^7.0.0", |
| 302 | + "babel-preset-es2015": "^6.24.1", |
| 303 | + "babel-preset-react": "^6.24.1", |
| 304 | + "less-loader": "^4.0.3", |
| 305 | + "react": "^15.5.4", |
| 306 | + "react-dom": "^15.5.4", |
| 307 | + "style-loader": "^0.16.1", |
| 308 | + "url-loader": "^0.5.8", |
| 309 | + "webpack": "^2.4.1" |
| 310 | + } |
| 311 | +} |
| 312 | + |
| 313 | +``` |
| 314 | + |
| 315 | +## 执行打包 |
| 316 | +在命令行执行`webpack`命令 |
| 317 | + |
| 318 | + |
| 319 | +## 安装并启用webpack-dev-server |
| 320 | + |
| 321 | +> 想不想让你的浏览器监测你都代码的修改,并自动刷新修改后的结果,其实Webpack提供一个可选的本地开发服务器,这个本地服务器基于node.js构建,可以实现你想要的这些功能,不过它是一个单独的组件,在webpack中进行配置之前需要单独安装它作为项目依赖 |
| 322 | +``` |
| 323 | +npm install --save-dev webpack-dev-server |
| 324 | +``` |
| 325 | +在webpack.config.js增加devServer的配置 |
| 326 | +```js |
| 327 | +//__dirname是node.js中的一个全局变量,它指向当前执行脚本所在的目录 |
| 328 | +module.exports = { //注意这里是exports不是export |
| 329 | + devtool: 'eval-source-map', //生成Source Maps,这里选择eval-source-map |
| 330 | + entry: __dirname + "/app/main.js", //唯一入口文件 |
| 331 | + output: { //输出目录 |
| 332 | + path: __dirname + "/build", //打包后的js文件存放的地方 |
| 333 | + filename: 'bundle.js', //打包后的js文件名 |
| 334 | + }, |
| 335 | + module: { |
| 336 | + loaders: [{ |
| 337 | + test: /\.jsx?$/, |
| 338 | + exclude: /node_modules/, //屏蔽不需要处理的文件(文件夹)(可选) |
| 339 | + loader: 'babel-loader' |
| 340 | + //npm install babel-loader |
| 341 | + //npm install babel-core |
| 342 | + }, { |
| 343 | + test: /\.css$/, |
| 344 | + loader: 'style-loader!css-loader' |
| 345 | + }, { |
| 346 | + test: /\.less$/, |
| 347 | + loader: 'style-loader!css-loader!less-loader' |
| 348 | + }, { |
| 349 | + test: /\.(png|jpg)$/, |
| 350 | + loader: 'url-loader?limit=25000' |
| 351 | + }] |
| 352 | + }, |
| 353 | + devServer: { |
| 354 | + contentBase: './build', //默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到"build"目录) |
| 355 | + historyApiFallback: true, //在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html |
| 356 | + inline: true, //设置为true,当源文件改变时会自动刷新页面 |
| 357 | + port: 8080, //设置默认监听端口,如果省略,默认为"8080" |
| 358 | + } |
| 359 | +}; |
| 360 | +``` |
| 361 | + |
| 362 | +在命令行执行`webpack-dev-server`命令就会运行服务器 |
| 363 | +``` |
| 364 | +webpack-dev-server |
| 365 | +``` |
| 366 | +如果需要停止服务,在终端按两次`ctrl+c` |
| 367 | + |
| 368 | + |
| 369 | +# 思考 |
| 370 | + |
| 371 | +- webpack和gulp的区别 |
| 372 | + |
| 373 | +- webpack的四大概念入口(entry)输出(output)loader插件(plugins) |
| 374 | + |
| 375 | +- webpack如何实现模块化的 |
| 376 | + |
| 377 | +- webpack的打包后执行代码的原理`eval("console.log(1)")` |
0 commit comments