webpack 入门 大全学习笔记
- 新建文件夹,命名
webpack project
,在命令行中找到此位置。使用:
//全局安装
npm install webpack -g
//安装到项目目录
npm install webpacl --save-dev
- 在新建
package.json
文件,这是一个标准的 npm 说明文件。在命令行输入npm init
即可自动生成本文件(文件生成过程中所需参数均可不填); - 回到之前的空文件夹,并创建 app 与 piblic 两个文件夹。其中 app文件夹存放原始数据和我们将写的JavaScript模块。public 文件夹用来存放之后后浏览器读取的文件(包括使用webpack 打包生成的js文件以及一个
index.html
文件)。接下来再创建三个文件夹中:
- index.html –放在public文件夹中;
- Greeter.js –放在app文件夹中;
- main.js –放在app文件夹中。
在 index.html 中写入最基本的html代码,它在这里的目的在于引入打包之后的js文件。
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webpack test</title>
</head>
<body>
<div id="root">
</div>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
在Greeter.js 中定义一个返回包含问候信息的html元素的函数,并依据 CommonJS规范导出这个函数为一个模块。
//Greete.js
module.exports = function(){
var greet = document.createElement('div');
greet.textContent = "Hi this from Greeter.js";
return greet;
}
在main.js 文件中 引入Greeter.js文件,并添加到html文件中。
//main.js
const greeter = require('./Greeter.js');
documemt.querySelector('#root').appendChild(greeter());
正式使用 webpack
webpack 可以在终端使用,基本使用方法如下:
# {extry file}出填写入口文件的路径,本文中就是上述main.js的路径,
# {destination for bundled file}处填写打包文件的存放路径
# 填写路径的时候不用添加{}
webpack {entry file} {destination for bundled file}
配置webpack
在练习文件夹下新建 webpack.config.js
,写入一下基本配置:
module.exports = {
entry:__dirname + "/app/main.js",//入口文件
output:{
path:__dirname +"/public/",//打包后的文件存放的地方
filename:"bundle.js" //打包后输出文件夹的名字
}
}
设置完毕后,只需在命令行中输入 webpack
执行,即可。
继续对 npm 进行配置后可以在命令行中使用简单的 npm start 命令来替代上述命令。在 package.json
文件中 对 scripts
对象进行相关设置即可,设置方法如下:
// + 代表新增。- 代表删除
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "start":"webpack"
},
webpack 的强大功能
生成Source Maps (使调试更容易)
在 webpack.config.js
中进行配置:
module.exports = {
+ devtool: 'eval-source-map',
entry: __dirname + "/app/main.js", //入口文件
output: {
path: __dirname + "/public/", //打包后的文件存放的地方
filename: "bundle.js" //打包后输出文件夹的名字
}
}
使用webpack 构建本地服务器
让浏览器监听你的代码的修改,并自动刷新显示后的结果。安装组件:
npm install webpack-dev-server --save-dev
继续配置 webpack.config.js
:
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js", //入口文件
output: {
path: __dirname + "/public/", //打包后的文件存放的地方
filename: "bundle.js" //打包后输出文件夹的名字
},
+ devServer: {
+ contentBase: "./public/", //本地服务器所加载的页面所在的目录
+ historyApiFallback: true, //不跳转
+ inline: true, //实时刷新
+ // port:8080 //设置监听端口。默认8080;
}
}
在 package.json
中的scripts对象中添加如下命令,用以开启本地服务器:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack",
+ "server":"webpack-dev-server --open"
},
在命令行中输入npm run server
即可在本地的8080(默认端口)查看结果。
Loaders
Loaders 需要单独安装并且需要在webpack.config.js
中的 modules
关键字下进行配置。Loaders 的配置包括以下几个方面:
- test:一个用以匹配loaders所处理文件的扩展名的正则表达式(必须);
- loader:loader的名称(必须);
- include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
- query:为loaders提供额外的设置选项(可选).
不过在配置loader之前,我们把`Greeter.js`里的问候消息放在一个单独的`JSON`文件里,并通过合适的配置使`Greeter.js`可以读取该`JSON`文件的值,各文件修改后的代码如下:
在 public文件中创建如下 JSON 文件(命名为:`config.json`):
{
"greetText":"Hi this message from /public/config.json"
}
更新后的 Greeter.js
:
+ var config = require('../public/config.json');
module.exports = function() {
var greet = document.createElement('div');
+ greet.textContent = config.greetText;
return greet;
}
Babel 的安装与配置
一次性的安装依赖包:
// npm一次性安装多个依赖模块,模块之间用空格隔开
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
在webpack 中的webpack.config.js
添加如下配置:
+ module: {
+ rules: [{
+ test: /(\.jsx|\.js)$/,
+ use: {
+ loader: "babel-loader",
+ options: {
+ presets: ["es2015", "react"]
+ }
+ },
+ exclude: /node_modules/
+ }]
+ }
安装 react 以及 reactdom:
接下来使用ES6 的语法,更新Greeter.js
,并返回一个React组件:
+ import React,{Component} from 'react'
+ import config from '../public/config.json';
+ class Greeter extends Component{
+ render(){
+ return(
+ <div>
+ {config.greetText}
+ </div>
+ );
+ }
+ }
+ export default Greeter
修改main.js
如下:
+ import React from 'react';
+ import {render} from 'react-dom';
+ import Greeter from './Greeter'
+ render(<Greeter />, document.getElementById('root'));
重新使用npm start
打包,会在http://localhost:8080/
看到相应输出。这说明react 和 es6 被正常打包了。
一切皆模块
CSS
//安装
npm install style-loader css-loader --save-dev
继续在webpack.config.js
中添加module配置:
module: {
rules: [{
。。。},
+ {
+ test:/\.css$/,
+ use:[{
+ loader:"style-loader"
+ },{
+ loader:"css-loader"
+ }]
+ }]
}
接下来,在app文件夹中创建一个名字为“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;
}
我们这里例子中用到的webpack
只有单一的入口,其它的模块需要通过 import, require, url等与入口文件建立其关联,为了让webpack
能找到”main.css
“文件,我们把它导入”main.js
“中,如下:
//main.js
+ import './main.css'; //导入css文件。
上面的代码说明webpack是怎么把css当做模块看待的,咱们继续看一个更加真实的css模块实践。
CSS module
最近有一个叫做 CSS modules 的技术就意在把JS的模块化思想带入CSS中来,通过CSS模块,所有的类名,动画名默认都只作用于当前模块。Webpack从一开始就对CSS模块化提供了支持,在CSS loader中进行配置后,你所需要做的一切就是把”modules“传递到所需要的地方,然后就可以直接把CSS的类名传递到组件的代码中,且这样做只对当前组件有效,不必担心在不同的模块中使用相同的类名造成冲突。具体的代码如下:
//webpack.config.js
{
test: /\.css$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader",
+ options:{
+ modules:true
+ }
}]
}
继续:
在app文件夹下创建一个Greeter.css
文件:
.root{
background-color: #eee;
padding:10px;
border:3px solid #ccc;
}
导入 .root
到Greeter.js
中:
import React, {Component} from 'react'
import config from '../public/config.json';
+ import styles from './Greeter.css'; //导入css样式
class Greeter extends Component {
render() {
return (
+ <div className={styles.root}>
{config.greetText}
</div>
);
}
}
export default Greeter
在命令行中打包,在打开index.html文件查看效果。
CSS 预处理器
css 预处理器可以将特殊类型的语句转化为浏览器可识别的CSS语句。
在 webpack 里使用相关 loaders进行配置就可以使用了。以下是常用的CSS 处理loaders:
- Less Loader
- Sass Loader
- Stylus Loader
还有一个 PostCSS,可以帮助CSS实现更多功能。举例来说,使用PostCSS为CSS代码自动添加适应不同浏览器的CSS 前缀。
首先安装postcss-loader
和autoprefixer
(自动添加前缀的插件)
npm install postss-loader autoprefixer --save-dev
接下来,在webpack 配置文件webpack.config.js
中添加postcss-loader
,在根目录新建 postcss.config.js
,并添加如下代码之后,重新使用 npm start
打包时,写的css会自动根据 Can i use 里的数据添加不同前缀了。
//webpack.config.js
module: {
rules: [{
。。。
}, { test: /\.css$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
modules: true
}
},{
+ loader:"postcss-loader"
}]
}]
}
//postcss.config.js
+ module.exports = {
+ plugins: [
+ require('autoprefixer')
+ ]
+ }
插件(Plugins)
插件(Plugins)是用来拓展Webpack功能的,它们会在整个构建过程中生效,执行相关的任务。
Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个,插件并不直接操作单个文件,它直接对整个构建过程其作用。
使用插件的方法
要使用某个插件,需要使用 npm 安装它,然后要做的就是在 webpack配置中的plugins 关键字部分添加该插件的一个实例(plugins 是一个数组),继续上面的例子。给其添加一个给打包后代码添加版权声明的插件(BannerPlugin)
+ const webpack = require('webpack');
module.exports = {
。。。
module:{
。。。
},
+ plugins: [
+ new webpack.BannerPlugin('版权所有,翻版必究')
+ ]
}
HtmlWebpackPlugin
这个插件的作用是一句一个简单index.html
模板,生成一个自动引用你打包后的JS文件的新的index.html。这在每次生成的js文件名称不同时非常有用(比如添加了hash值);
安装:
npm install html-webpack-plugin --save-dev
这个插件自动完成了我们之前手动做的一些事情,在正式使用之前需要对一直以来的项目结构做一些更改:
1. 移除public文件夹。利用此插件,index.html文件会自动生成。此外,css已经通过前面的操作打包到js中了。
2. 在app目录下,创建一个 index.tmpl.html
文件模板,这个模板包含 title 等必须元素,在编译过程中,插件会依据此模板生成最终的html 页面,会自动添加所以来的css,js,favicon, index.tmpl.html 中的模板源代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webpack test module</title>
</head>
<body>
<div id="root">
</div>
</body>
</html>
- 更新webpack的配置文件:添加plugin及其参数,修改output输出文件目录,修改devServer的目录。方法同上,新建一个 build 文件夹用来存放最终的输出文件。
//webpack.config.js
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
。。。
output: {
+ path: __dirname + "/build/", //打包后的文件存放的地方
filename: "bundle.js" //打包后输出文件夹的名字
},
devServer: {
+ contentBase: "./build/", //本地服务器所加载的页面所在的目录
historyApiFallback: true, //不跳转
inline: true, //实时刷新
// port:8080 //设置监听端口。默认8080;
},
plugins: [
new webpack.BannerPlugin('版权所有,翻版必究'),
+ new HtmlWebpackPlugin({
+ template: __dirname + "/app/index.tmpl.html" //new 一个这个插件的实例,并传入相关的参数
+ })
]
}
修改,app文件夹下的Greeter.js 文件:
- import config from './public/config.json';
+ import config from './config.json';
在本目录新建 config.json
,内同同public文件中中的config.json。
执行 npm start
会在build 文件夹下面发现bundle.js
index.html
两个文件。
Hot Module Replacement
Hot Module Replacement
(HMR)也是webpack里很有用的一个插件,它允许你在修改组件代码后,自动刷新实时预览修改后的效果。
在webpack中实现HMR也很简单,只需要做两项配置:
- 在webpack配置文件中添加HMR插件;
- 在 webpack Dev Server中添加“hot”参数;
不过配置完这些后,JS模块其实还是不能自动热加载的,还需要在你的JS模块中执行一个Webpack提供的API才能实现热加载,虽然这个API不难使用,但是如果是React模块,使用我们已经熟悉的Babel可以更方便的实现功能热加载。
整理下我们的思路,具体实现方法如下
Babel和webpack是独立的工具
- 二者可以一起工作
- 二者都可以通过插件拓展功能
- HMR是一个webpack插件,它让你能浏览器中实时观察模块修改后的效果,但是如果你想让它工作,需要对模块进行额外的配额;
- Babel有一个叫做react-transform-hrm的插件,可以在不对React模块进行额外的配置的前提下让HMR正常工作;
继续上例,进行配置:
//webpack.config.js
devServer: {
contentBase: "./build/", //本地服务器所加载的页面所在的目录
historyApiFallback: true, //不跳转
inline: true, //实时刷新
+ hot:true,
// port:8080 //设置监听端口。默认8080;
},
plugins: [
new webpack.BannerPlugin('版权所有,翻版必究'),
new HtmlWebpackPlugin({
template: __dirname + "/app/index.tmpl.html" //new 一个这个插件的实例,并传入相关的参数
}),
+ new webpack.HotModuleReplacementPlugin() //热加载插件
]
安装 react-transform-hmr
npm install babel-plugin-react-transform react-transform-hmr --save-dev
由于babel配置增加,所以新建.babelrc
文件来统一babel配置设置。
//.babelrc
{
"presets":["react","es2015"],
"env":{
"development":{
"plugins":[["react-transform",{
"transforms":[{
"transform":"react-transform-hmr",
"imports":["react"],
"locals":["module"]
}]
}]]
}
}
}
//webpack.config.js
rules: [{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader",
- // options: {
- // presets: ["es2015", "react"]
- // }
},
exclude: /node_modules/
},{...}]
现在当你使用React时,可以热加载模块了,每次保存就能在浏览器上看到更新内容。
产品阶段的构建
目前为止,我们已经使用webpack构建了一个完整的开发环境。
但是在产品阶段,可能还需要对打包的文件进行额外的处理,比如说优化,压缩,缓存以及分离CSS和JS。
对于复杂的项目来说,需要复杂的配置,这时候分解配置文件为多个小的文件可以使得事情井井有条,以上面的例子来说,我们创建一个webpack.production.config.js
的文件,在里面加上基本的配置,它和原始的webpack.config.js
很像,如下:
// webpack.production.config.js
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 一个这个插件的实例,并传入相关的参数
}),
new webpack.HotModuleReplacementPlugin()//热加载插件
],
};
//package.json
{
"name": "webpackproject",
"version": "1.0.0",
"description": "for webpack test",
"main": "index.js",
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1",
"webpack": "^3.5.4"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.25.0",
"babel-loader": "^7.1.1",
"babel-plugin-react-transform": "^2.0.2",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"css-loader": "^0.28.4",
"html-webpack-plugin": "^2.30.1",
"postcss-loader": "^2.0.6",
"react-transform-hmr": "^1.0.4",
"style-loader": "^0.18.2",
"webpack-dev-server": "^2.7.1"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack",
"server": "webpack-dev-server --open",
"build": " set NODE_ENV=production &&webpack --config ./webpack.production.config.js --progress",
},
"author": "wang",
"license": "ISC"
}
优化插件
通过npm安装。一下插件可以完成产品发布阶段所需的功能:
- OccurenceOrderPlugin:为组件分配ID,通过这个插件webpack 可以分析和优先考虑使用最多的模块,并未他们分配最小的ID。
- UglifyJsPlugin:压缩JS代码;
- ExtractTextWebpackPlugin:分离CSS和JS文件;
继续使用上例查看如何添加他们。OccurenceOrder 和 UglifyJS plugins 都是内置插件,你需要做的只是安装其它非内置插件:
npm install --save-dev extract-text-webpack-plugin
在配置文件中的plugins后引用他们:
//webpack.production.config.js
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
module: {
rules: [
{
test: /\.css$/,
+ use: ExtractTextPlugin.extract({
+ fallback: "style-loader",
+ use: [
- // {
- // loader: "style-loader"
- // },{
loader: "css-loader",
options: {
modules: true
}
}, {
loader: "postcss-loader"
}]
})
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
]
}
这是在命令行中运行“npm run build” 可以看到在“build”文件夹下新生成了“style.css”文件。