Webpack学习总结

来源:互联网 发布:qq采集分析软件 编辑:程序博客网 时间:2024/06/10 03:39

Webpack学习总结

  • Webpack学习总结
    • Webpack 与 Gulp Grunt 对比
    • 安装
      • 1 创建packagejson文件
      • 2 安装Webpack作为依赖包
      • 3 创建目录文件夹
    • 使用
      • 1 编写基础代码
      • 2 命令行基本使用
      • 3 通过配置文件使用
      • 4 更快捷地执行打包任务
    • 功能扩展
      • 1 生成Source Maps简化调试
      • 2 构建本地服务器
      • 3 Loaders
        • 31 实例1配置读取 json 文件
        • 32 实例2配置 babel
        • 33 实例3配置 css-loader style-loader
        • 34 实例4配置 CSS module
        • 35 实例5配置 CSS预处理器
    • 插件
      • 1 区别 Loaders 和 Plugins
      • 2 使用插件
        • 21 实例1banner-plugin
        • 22 实例2HtmlWebpackPlugin
        • 23 实例3Hot Module Replacement
    • 产品阶段的构建
      • 1 创建 webpackproductionconfigjs 文件
      • 2 配置 packagejson
      • 3 优化插件
      • 4 缓存

1. Webpack 与 Gulp / Grunt 对比

WebPack : 模块化解决方案(模块打包机),能够分析项目结构,找到JavaScript模块及浏览器不能直接运行的拓展语言(Scss,TypeScript等),转换和打包为合适的格式供浏览器使用。WebPack把项目当做一个整体,通过一个给定的主文件(如:index.js)开始找到项目的所有依赖文件,使用loaders处理,最后打包为一个(或多个)浏览器可识别的JavaScript文件

Gulp/Grunt : 前端开发流程优化工具,在配置文件中指明对某些文件进行编译、组合、压缩等任务的具体步骤并自动完成

2. 安装

2.1 创建package.json文件

# 创建标准的npm说明文件npm init# 回车默认即可

2.2 安装Webpack作为依赖包

# 全局安装npm install -g webpack# 安装到项目目录npm install --save-dev webpack

2.3 创建目录文件夹

创建两个文件夹:app 和 public,app文件夹存放原始数据和编写的JavaScript模块,public文件夹存放供浏览器读取的文件(包括使用webpack打包生成的js文件及一个index.html文件)

webpack sample project|-- node_modules/|-- app/|   |-- Greeter.js|   |-- main.js|-- public/|   |--index.html|-- package.json

3. 使用

3.1 编写基础代码

index.html 用于测试引入打包后的js文件(暂定名为bundle.js

<!-- index.html --><!DOCTYPE html><html lang="en">  <head>    <meta charset="utf-8">    <title>Webpack Sample Project</title>  </head>  <body>    <div id='root'>    </div>    <script src="bundle.js"></script>  </body></html>

Greeter.js 中定义一个返回包含问候信息的html元素的函数,并依据CommonJS规范导出这个函数为一个模块

// Greeter.jsmodule.exports = function() {  var greet = document.createElement('div');  greet.textContent = "Hi there and greetings!";  return greet;};

main.jsGreeter模块返回的节点插入页面。

//main.js const greeter = require('./Greeter.js');document.querySelector("#root").appendChild(greeter());

3.2 命令行基本使用

webpack可以在终端中使用,在基本的使用方法如下:

# {extry file} 处填写入口文件的路径,本文中就是上述main.js的路径,# {destination for bundled file} 处填写打包文件的存放路径# 填写路径的时候不用添加{}webpack {entry file} {destination for bundled file}

未全局安装webpack时需要额外指定其在node_modules中的地址

# webpack非全局安装的情况,后同node_modules/.bin/webpack app/main.js public/bundle.js

3.3 通过配置文件使用

创建 websocket 配置文件 webpack.config.js

module.exports = {  entry:  __dirname + "/app/main.js",// 唯一入口文件  output: {    path: __dirname + "/public",// 打包后的文件存放路径    filename: "bundle.js"// 打包后输出文件的文件名  }}

:“__dirname” 是 node.js 中的全局变量,指向当前执行脚本所在的目录

打包文件只需命令行执行 webpack,将自动引用 webpack.config.js 文件中的配置选项

webpack

3.4 更快捷地执行打包任务

npm进行配置后可以使用 npm 引导任务执行,在命令行中使用简单的 npm start 命令替代略微繁琐的命令 node_modules/.bin/webpack,在 package.json 中对 scripts 对象进行相关设置:

{  "name": "webpack-sample-project",  "version": "1.0.0",  "description": "Sample webpack project",  "scripts": {    "start": "webpack" // 修改此处,JSON文件不支持注释,引用时清除  },  "author": "csxiaoyao",  "license": "ISC",  "devDependencies": {    "webpack": "^1.12.9"  }}

注:

  1. package.json 中的 script 会按一定顺序寻找命令对应位置(包含本地的node_modules/.bin),所以全局或局部安装的Webpack都不需要指明详细的路径
  2. npm的start命令特殊,npm start 可直接执行其对应的命令,而如果脚本名称不是 start,需执行 npm run {script name}npm run build
npm start

4. 功能扩展

4.1 生成Source Maps(简化调试)

通过配置 devtoolwebpack 可以在打包时生成 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是一个很好的选项,但只应该开发阶段使用,对 webpack.config.js进行如下配置:

module.exports = {  devtool: 'eval-source-map',  ...}

4.2 构建本地服务器

Webpack 提供了一个基于node.js构建的可选的本地开发服务器,可以让浏览器监听代码修改,并自动刷新显示,安装依赖并配置,更多配置参考 https://webpack.js.org/configuration/dev-server

npm install --save-dev webpack-dev-server
devserver配置选项 功能描述 contentBase 默认为根文件夹提供本地服务器(本例设置到“public”目录) port 设置默认监听端口,默认为”8080“ inline 设置为true,当源文件改变时自动刷新页面 historyApiFallback 依赖 HTML5 history API,如果设置为true,所有跳转将指向index.html(开发单页应用)

修改配置文件 webpack.config.js

module.exports = {  ...  devServer: {    contentBase: "./public",// 本地服务器根目录    historyApiFallback: true,// 不跳转    inline: true// 实时刷新  } }

package.json 中的 scripts 对象中添加命令以开启本地服务器

"scripts": {  "test": "echo \"Error: no test specified\" && exit 1",  "start": "webpack",  "server": "webpack-dev-server --open"},

开启本地服务器,在8080端口查看结果

npm run server

4.3 Loaders

通过使用不同的loaderwebpack能调用外部的脚本或工具,实现对不同格式的文件处理,比如分析转换scss为css,或把下一代的JS文件(ES6,ES7)转换为现代浏览器兼容的JS文件,对React可以把JSX文件转换为JS文件

Loaders需单独安装并在 webpack.config.js 中配置 modules,Loaders配置包括:

  • test:匹配loaders处理文件的拓展名的正则表达式(必须)
  • loader:loader名称(必须)
  • include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选)
  • query:为loaders提供额外的设置选项(可选)

4.3.1 实例1:配置读取 json 文件

Greeter.js 中的问候消息单独存放于 config.json

{  "greetText": "Hi there and greetings from JSON!"}

更新 Greeter.js

var config = require('./config.json');module.exports = function() {  var greet = document.createElement('div');  greet.textContent = config.greetText;  return greet;};

:由于webpack3.*/webpack2.*已内置可处理JSON文件,所以无需再添加webpack1.*需要的json-loader

4.3.2 实例2:配置 babel

Babel是一个编译JavaScript的平台(ES6、ES7、JSX…),Babel有一些模块化的包,核心功能位于babel-core的npm包中,webpack可以把其不同的包整合在一起使用,对每个需要的功能或拓展需要安装单独的包(如解析Es6的babel-preset-es2015包和解析JSX的babel-preset-react包)

  1. 安装依赖模块
# npm一次性安装多个依赖模块,模块之间用空格隔开npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
  1. 配置 webpack
module.exports = {    ...    module: {        rules: [            {                test: /(\.jsx|\.js)$/,                use: {                    loader: "babel-loader",                    options: {                        presets: [                            "es2015", "react"                        ]                    }                },                exclude: /node_modules/            }        ]    }};
  1. 安装 react
npm install --save react react-dom
  1. 使用ES6语法,更新Greeter.js并返回一个React组件
// Greeter.jsimport React, {Component} from 'react'import config from './config.json';class Greeter extends Component{  render() {    return (      <div>        {config.greetText}      </div>    );  }}export default Greeter
  1. 修改main.js,使用ES6的模块定义和渲染Greeter模块
import React from 'react';import {render} from 'react-dom';import Greeter from './Greeter';render(<Greeter />, document.getElementById('root'));
  1. 重新打包
npm start
  1. 访问 localhost:8080 查看效果

  2. 使用单独的配置文件配置Babel

为简化Babel配置,把babel的配置选项单独放在 .babelrc 配置文件中(webpack会自动调用)

module.exports = {   ...    module: {        rules: [            {                test: /(\.jsx|\.js)$/,                use: {                    loader: "babel-loader"                },                exclude: /node_modules/            }        ]    }};

新建 .babelrc 文件

{  "presets": ["react", "es2015"]}

4.3.3 实例3:配置 css-loader & style-loader

webpack提供两个工具处理样式表,css-loader使开发者能够使用类似@importurl(...)的方法实现 require()的功能,style-loader将所有的计算后的样式加入页面中,二者组合把样式表嵌入webpack打包后的JS文件中

  1. 安装依赖模块
npm install --save-dev style-loader css-loader
  1. 配置 webpack
module.exports = {   ...    module: {        rules: [            {                test: /(\.jsx|\.js)$/,                use: {                    loader: "babel-loader"                },                exclude: /node_modules/            },            {                test: /\.css$/,                use: [                    {                        loader: "style-loader"                    }, {                        loader: "css-loader"                    }                ]            }        ]    }};

注:注意此处对同一个文件引入多个loader的方法

  1. 在app文件夹中创建 main.css 文件
/* main.css */html {  box-sizing: border-box;  -ms-text-size-adjust: 100%;  -webkit-text-size-adjust: 100%;}*, *:before, *:after {  box-sizing: inherit;}body {  margin: 0;  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;}h1, h2, h3, h4, h5, h6, p, ul {  margin: 0;  padding: 0;}
  1. 入口文件导入 main.css 文件
//main.jsimport React from 'react';import {render} from 'react-dom';import Greeter from './Greeter';import './main.css';//使用require导入css文件render(<Greeter />, document.getElementById('root'));

4.3.4 实例4:配置 CSS module

CSS modules 技术意在把 JS 的模块化思想带入 CSS 中,通过CSS模块,所有的类名,动画名默认都只作用于当前模块,不必担心在不同的模块中使用相同的类名造成冲突

  1. 配置 webpack
module.exports = {    ...    module: {        rules: [            {                test: /(\.jsx|\.js)$/,                use: {                    loader: "babel-loader"                },                exclude: /node_modules/            },            {                test: /\.css$/,                use: [                    {                        loader: "style-loader"                    }, {                        loader: "css-loader",                        options: {                            modules: true                        }                    }                ]            }        ]    }};
  1. 在app文件夹下创建 Greeter.css 文件
.root {  background-color: #eee;  padding: 10px;  border: 3px solid #ccc;}
  1. 导入 .rootGreeter.js 中,相同的类名也不会造成不同组件之间的污染
import React, {Component} from 'react';import config from './config.json';import styles from './Greeter.css';//导入class Greeter extends Component{  render() {    return (      <div className={styles.root}>//添加类名        {config.greetText}      </div>    );  }}export default Greeter
  1. CSS modules 更多详见官方文档https://github.com/css-modules/css-modules

4.3.5 实例5:配置 CSS预处理器

SassLess 等预处理器是对原生CSS的拓展,允许使用 variables, nesting, mixins, inheritance 等不存在于CSS中的特性来写CSS,CSS预处理器可将其转化为浏览器可识别的CSS语句,常用的CSS 处理loaders:

  • Less Loader
  • Sass Loader
  • Stylus Loader

此外存在一个更强大的CSS的处理平台-PostCSS https://github.com/postcss/postcss ,例如使用PostCSS为CSS代码自动添加适应不同浏览器的CSS前缀

  1. 安装postcss-loaderautoprefixer(自动添加前缀插件)
npm install --save-dev postcss-loader autoprefixer
  1. 配置 webpack
//webpack.config.jsmodule.exports = {    ...    module: {        rules: [            {                test: /(\.jsx|\.js)$/,                use: {                    loader: "babel-loader"                },                exclude: /node_modules/            },            {                test: /\.css$/,                use: [                    {                        loader: "style-loader"                    }, {                        loader: "css-loader",                        options: {                            modules: true                        }                    }, {                        loader: "postcss-loader"                    }                ]            }        ]    }}
  1. 在根目录新建 postcss.config.js 文件
// postcss.config.jsmodule.exports = {    plugins: [        require('autoprefixer')    ]}
  1. 重新使用npm start打包,css会自动根据Can i use里的数据添加不同前缀

5. 插件

5.1 区别 Loaders 和 Plugins

loaders 在打包构建过程中处理源文件(JSX,Scss,Less..),一次处理一个

Plugins 直接作用于整个构建过程,不直接操作单个文件

5.2 使用插件

5.2.1 实例1:banner-plugin

添加版权声明插件,插件地址:https://webpack.js.org/plugins/banner-plugin ,修改配置文件,打包后的JS文件中会插入版权信息

const webpack = require('webpack');module.exports = {    ...    plugins: [        new webpack.BannerPlugin('版权所有,翻版必究')    ],};

5.2.2 实例2:HtmlWebpackPlugin

HtmlWebpackPlugin 插件依据一个简单的index.html模板,生成一个自动引用打包后的JS文件的新index.html (添加hash值给js文件生成版本)

  1. 安装依赖
npm install --save-dev html-webpack-plugin
  1. 修改项目结构

移除public文件夹,index.html 文件会自动生成,在app目录下创建 index.tmpl.html文件模板(包含title等必须元素),编译过程中插件会自动添加所依赖的 css、js、favicon 等文件,并生成最终的html页面

<!-- index.tmpl.html --><!DOCTYPE html><html lang="en">  <head>    <meta charset="utf-8">    <title>Webpack Sample Project</title>  </head>  <body>    <div id='root'>    </div>  </body></html>
  1. 更新webpack配置文件,新建 build 文件夹存放最终的输出文件
const webpack = require('webpack');const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {    entry: __dirname + "/app/main.js",    output: {        path: __dirname + "/build",        filename: "bundle.js"    },    ...    plugins: [        new webpack.BannerPlugin('版权所有,翻版必究'),        new HtmlWebpackPlugin({            template: __dirname + "/app/index.tmpl.html"// 创建插件实例,并传入相关参数        })    ],};
  1. 执行npm start,build文件夹下生成 bundle.jsindex.html

5.2.3 实例3:Hot Module Replacement

Hot Module Replacement(HMR)允许在修改组件代码后自动刷新实时预览

  1. 安装react-transform-hmr
npm install --save-dev babel-plugin-react-transform react-transform-hmr
  1. 配置Babel
// .babelrc{  "presets": ["react", "es2015"],  "env": {    "development": {    "plugins": [["react-transform", {       "transforms": [{         "transform": "react-transform-hmr",         "imports": ["react"],         "locals": ["module"]       }]     }]]    }  }}
  1. 配置 webpack
const webpack = require('webpack');const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {    entry: __dirname + "/app/main.js",    output: {        path: __dirname + "/build",        filename: "bundle.js"    },    devtool: 'eval-source-map',    devServer: {        contentBase: "./public",//本地服务器所加载的页面所在的目录        historyApiFallback: true,//不跳转        inline: true,        hot: true    },    module: {        rules: [            {                test: /(\.jsx|\.js)$/,                use: {                    loader: "babel-loader"                },                exclude: /node_modules/            },            {                test: /\.css$/,                use: [                    {                        loader: "style-loader"                    }, {                        loader: "css-loader",                        options: {                            modules: true                        }                    }, {                        loader: "postcss-loader"                    }                ]            }        ]    },    plugins: [        new webpack.BannerPlugin('版权所有,翻版必究'),        new HtmlWebpackPlugin({            template: __dirname + "/app/index.tmpl.html"// 创建插件实例,并传入相关参数        }),        new webpack.HotModuleReplacementPlugin()// 热加载插件    ],};
  1. 使用React时可以热加载模块,每次保存能在浏览器上看到更新内容

6. 产品阶段的构建

在产品阶段,还需要对打包的文件进行额外的处理,如优化、压缩、缓存及分离CSS和JS

6.1 创建 webpack.production.config.js 文件

// webpack.production.config.jsconst webpack = require('webpack');const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {    entry: __dirname + "/app/main.js",    output: {        path: __dirname + "/build",        filename: "bundle.js"    },    devtool: 'eval-source-map',    devServer: {        contentBase: "./public",//本地服务器所加载的页面所在的目录        historyApiFallback: true,//不跳转        inline: true,        hot: true    },    module: {        rules: [            {                test: /(\.jsx|\.js)$/,                use: {                    loader: "babel-loader"                },                exclude: /node_modules/            },            {                test: /\.css$/,                use: [                    {                        loader: "style-loader"                    }, {                        loader: "css-loader",                        options: {                            modules: true                        }                    }, {                        loader: "postcss-loader"                    }                ]            }        ]    },    plugins: [        new webpack.BannerPlugin('版权所有,翻版必究'),        new HtmlWebpackPlugin({            template: __dirname + "/app/index.tmpl.html"// 创建插件实例,并传入相关参数        }),        new webpack.HotModuleReplacementPlugin()// 热加载插件    ],};

6.2 配置 package.json

//package.json{  "name": "test",  "version": "1.0.0",  "description": "",  "main": "index.js",  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1",    "start": "webpack",    "server": "webpack-dev-server --open",    "build": "NODE_ENV=production webpack --config ./webpack.production.config.js --progress"  },  "author": "csxiaoyao",  "license": "ISC",  "devDependencies": {    ...  },  "dependencies": {    "react": "^15.6.1",    "react-dom": "^15.6.1"  }}

6.3 优化插件

  • OccurenceOrderPlugin:(内置)为组件分配ID,分析和优先考虑使用最多的模块并为它们分配最小的ID
  • UglifyJsPlugin:(内置)压缩JS代码
  • ExtractTextPlugin:分离CSS和JS文件

    1. 安装依赖
npm install --save-dev extract-text-webpack-plugin
  1. 配置 webpack
// webpack.production.config.jsconst 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.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: [                    {                        loader: "style-loader"                    }, {                        loader: "css-loader",                        options: {                            modules: true                        }                    }, {                        loader: "postcss-loader"                    }                ]            }        ]    },    plugins: [        new webpack.BannerPlugin('版权所有,翻版必究'),        new HtmlWebpackPlugin({            template: __dirname + "/app/index.tmpl.html"        }),        new webpack.optimize.OccurrenceOrderPlugin(),        new webpack.optimize.UglifyJsPlugin(),        new ExtractTextPlugin("style.css")    ],};
  1. 执行
npm run build

6.4 缓存

webpack可以把哈希值添加到打包的文件名中,添加特殊的字符串混合体([name], [id] and [hash])到输出文件名前

module.exports = {    ...    output: {        path: __dirname + "/build",        filename: "bundle-[hash].js"    },    ...};
原创粉丝点击