webpack 入门

ref:
什么是webpack?

webpack是一个模块打包器
webpack获取带依赖的模块并产生出与这些模块相对于的静态资源.

webpack的目标:
  • 拆分依赖树成块并按需加载
  • 让初始化加载时间更少
  • 每一个静态资源应该是一个模块
  • 能够集成第三方类库
  • 适用于大型项目
  • 能够定制模块打包的每一个部分
概念
  • Entry
  • Output
  • Loader
  • Plugins
环境配置
  • 首先需要安装node.js
  • 安装webpack npm install webpack -g 全局安装
  • 然后再npm init, 之后会自动创建package.json文件
  • 或者可以选择安装到你的项目目录
//安装到你的项目目录
npm install --save-dev webpack
用法
  • 执行webpack ,用法是webpack [entry] -o [Output] 。不要忘了加上 -o
# webpack非全局安装的情况
node_modules/.bin/webpack app/main.js -o public/bundle.js

eg node_modules/.bin/webpack app/main.js -o public/bundle.js --mode development

  • 可以优化一下webpack打包设置。在项目根目录上新建webpack.config.js,修改如下。有了这个配置文件,下次打包的时候只需要输入webpack(局部环境下输入node_modules/.bin/webpack) 即可进行打包。
module.exports = {
  entry:  __dirname + "/app/main.js",//已多次提及的唯一入口文件
  output: {
    path: __dirname + "/public",//打包后的文件存放的地方
    filename: "bundle.js"//打包后输出文件的文件名
    //注:“__dirname”是node.js中的一个全局变量,它指向当前执行脚本所在的目录。
  }
}
  • 可以把打包命令webpacknode_modules/.bin/webpack 写入到 package.json中。需要打包时直接运行npm start即可。
{
  "name": "mywebpack",
  "version": "1.0.0",
  "description": "May 9, webpack practice",
  "main": "index.js",
  "scripts": {
    "start":"webpack", //修改这里
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.8.1",
    "webpack-dev-server": "^3.1.4"
  }
}
  • 其他工具:生成Source Maps(使调试更容易)
    通过简单的配置,webpack就可以在打包时为我们生成的source maps,这为我们提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试。

    cheap-module-eval-source-map方法构建速度更快,但是不利于调试,推荐在大型项目考虑时间成本时使用。

    对小到中型的项目中,eval-source-map是一个很好的选项,再次强调你只应该开发阶段使用它,我们继续对上文新建的webpack.config.js,进行如下配置:
module.exports = {
  devtool: 'eval-source-map', //添加这里
  entry:  __dirname + "/app/main.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  }
}
  • 其他工具:使用webpack构建本地服务器。让浏览器监听代码的修改,并自动刷新显示修改后的结果。其实webpack提供一个可选的本地开发服务器,在webpack中进行配置之前需要单独安装它作为项目依赖。
    npm install --save-dev webpack-dev-server
    安装成功后,修改webpack.config.js如下:
module.exports = {
  devtool: 'eval-source-map', //source map
  entry:  __dirname + "/app/main.js",//已多次提及的唯一入口文件
  output: {
    path: __dirname + "/public",//打包后的文件存放的地方
    filename: "bundle.js"//打包后输出文件的文件名
  },
  // 以下添加
  devServer: {
    contentBase: "./public",//本地服务器所加载的页面所在的目录
    historyApiFallback: true,//不跳转
    inline: true//实时刷新
  } 
}
  • 其他设置: set mode to development/production。 有时候会遇到如下警告:

    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.config.js中设置:
module.exports = {
  devtool: 'eval-source-map', 
  mode:'development', //set 'mode' option to 'development'
  entry:  __dirname + "/app/main.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  },
  devServer: {
    contentBase: "./public",
    historyApiFallback: true,
    inline: true
  } 
}
Loaders
通过使用不同的loader,webpack有能力调用外部的脚本或工具,实现对不同格式的文件的处理。 Loaders需要单独安装并且需要在webpack.config.js中的modules关键字下进行配置,Loaders的配置包括以下几方面:
  • test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
  • loader:loader的名称(必须)
  • include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
  • query:为loaders提供额外的设置选项(可选)

在具体使用loaders之前我们先了解一下Babel

Babel

Babel其实是一个编译JavaScript的平台,它可以编译代码帮你达到以下目的:
让你能使用最新的JavaScript代码(ES6,ES7…),而不用管新标准是否被当前使用的浏览器完全支持;
让你能使用基于JavaScript进行了拓展的语言,比如React的JSX;

Babel的安装与配置
Babel其实是几个模块化的包,其核心功能位于称为babel-core的npm包中,webpack可以把其不同的包整合在一起使用,对于每一个你需要的功能或拓展,你都需要安装单独的包(用得最多的是解析Es6的babel-preset-env包和解析JSX的babel-preset-react包)。

我们先来一次性安装这些依赖包

// npm一次性安装多个依赖模块,模块之间用空格隔开
npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react

修改 webpack.config.js:

module.exports = {
  devtool: ...
  mode: ...
  entry: ...
  output: {
    ...
  },
  devServer: {
  ...
  },
  //新添加以下module
  module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: [
                            "env", "react"
                        ]
                    }
                },
                exclude: /node_modules/
            }
        ]
    }
}

这里我们用react进行测试。安装npm install --save react react-dom

接下来我们使用ES6的语法,更新Greeter.js并返回一个React组件

//Greeter,js
import React, {Component} from 'react'
import config from './config.json';

class Greeter extends Component{
  render() {
    return (
      <div>
        {config.greetText}
      </div>
    );
  }
}

export default Greeter

修改main.js如下,使用ES6的模块定义和渲染Greeter模块

// main.js
import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';

render(<Greeter />, document.getElementById('root'));

重新使用npm start打包,如果之前打开的本地服务器没有关闭,你应该可以在localhost:8080下看到与之前一样的内容,这说明react和es6被正常打包了。

CSS

webpack提供两个工具处理样式表,css-loaderstyle-loader,二者处理的任务不同,css-loader使你能够使用类似@import 和 url(…)的方法实现 require()的功能,style-loader将所有的计算后的样式加入页面中,二者组合在一起使你能够把样式表嵌入webpack打包后的JS文件中。

安装
npm install --save-dev style-loader css-loader

使用

//使用
module.exports = {

   ...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {//注意留意一下加载多个loader怎么写
                        loader: "style-loader"
                    }, {
                        loader: "css-loader"
                    }
                ]
            }
        ]
    }
};

在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;
}
  • 像模块一样使用”main.js”
    我们这里例子中用到的webpack只有单一的入口,其它的模块需要通过 import, require, url等与入口文件建立其关联,为了让webpack能找到”main.css“文件,我们把它导入”main.js “中,如下
//main.js
import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';
import './main.css';//使用require导入css文件

render(<Greeter />, document.getElementById('root'));
CSS module

被称为CSS modules的技术意在把JS的模块化思想带入CSS中来,通过CSS模块,所有的类名,动画名默认都只作用于当前模块。Webpack对CSS模块化提供了非常好的支持,只需要在CSS loader中进行简单配置即可,然后就可以直接把CSS的类名传递到组件的代码中,这样做有效避免了全局污染

module.exports = {

...
module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: [
                            "env", "react"
                        ]
                    }
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {//请注意这里对同一个文件引入多个loader的方法。
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {//css模块化,避免变量的全局污染
                            modules: true, // 指定启用css modules
                            localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的类名格式
                        }
                    }
                ]
            }
        ]
    }
};

下面在app文件夹下创建一个Greeter.css文件来进行一下测试:

// Greeter.js

import React, {Component} from 'react'
import config from './config.json';
import styles from './Greeter.css'; //导入Greeter.css进行css Module测试

class Greeter extends Component{
  render() { //使用cssModule添加类名的方法
    return (
        <div className={styles.root}> 
        {config.greetText}
        </div>
    );
  }
}

export default Greeter

发现css类名已被重命名。
这里写图片描述

CSS预处理器

SassLess 之类的预处理器是对原生CSS的拓展,它们允许你使用类似于variables, nesting, mixins, inheritance等不存在于CSS中的特性来写CSS,CSS预处理器可以这些特殊类型的语句转化为浏览器可识别的CSS语句.
参考: Sass, Less与CSS的区别

  • 在webpack里使用相关loaders进行配置就可以使用了,以下是常用的CSS 处理loaders:
    Less Loader
    Sass Loader
    Stylus Loader

其实也存在一个CSS的处理平台-PostCSS,它可以帮助你的CSS实现更多的功能,在其官方文档可了解更多相关知识。

举例来说如何使用PostCSS,我们使用PostCSS来为CSS代码自动添加适应不同浏览器的CSS前缀。

首先安装postcss-loaderautoprefixer(自动添加前缀的插件)

npm install --save-dev postcss-loader autoprefixer

接下来,在webpack配置文件中添加postcss-loader, 在根目录新建postcss.config.js,并添加如下代码之后,重新使用npm start打包时,你写的css会自动根据Can i use里的数据添加不同前缀了。

// postcss.config.js
module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}
插件(Plugins)

至此,本文已经谈论了处理JS的Babel和处理CSS的PostCSS的基本用法,它们其实也是两个单独的平台,配合webpack可以很好的发挥它们的作用。接下来介绍Webpack中另一个非常重要的功能-Plugins

Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个,插件并不直接操作单个文件,它直接对整个构建过程其作用。

  • 使用插件的方法
    需要使用npm安装它,然后要做的就是在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数组)

继续上面的例子,我们添加了一个给打包后代码添加版权声明的插件

//加入这行
const webpack = require('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
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
    plugins: [ //在module的同级位置加入plugins
        new webpack.BannerPlugin('版权所有,翻版必究')
    ],
};

再次npm run start之后,可以看到生成的bundle.js里出现:
这里写图片描述

有用的几个插件
HtmlWebpackPlugin

这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。这在每次生成的js文件名称不同时非常有用(比如添加了hash值)。

安装
npm install --save-dev html-webpack-plugin

这个插件自动完成了我们之前手动做的一些事情,在正式使用之前需要对一直以来的项目结构做一些更改:

  • 移除public文件夹,利用此插件,index.html文件会自动生成,此外CSS已经通过前面的操作打包到JS中了。
  • 在app目录下,创建一个index.tmpl.html文件模板,这个模板包含title等必须元素,在编译过程中,插件会依据此模板生成最终的html页面,会自动添加所依赖的 css, js,favicon等文件,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>
  • 删除public文件夹,更新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"
    },
    devtool: 'eval-source-map',
    devServer: {
        contentBase: "./build",//本地服务器所加载的页面所在的目录
        historyApiFallback: true,//不跳转
        inline: 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 一个这个插件的实例,并传入相关的参数
        })
    ],
};

最后npm run start一下,再npm run server ,可以看到build文件夹下生成了bundle.js和index.html。

文章后面还有其他插件的介绍,比如Hot Module Replacement,产品阶段的优化,插件的优化,缓存等内容的涉及。以后再补充吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值