webpack 学习笔记

本文主要分为:

  • 环境配置
  • 使用配置文件
  • CSS 处理
  • ES6 代码编辑
  • 文件压缩
  • SASS 处理
  • CSS 与 JS 分离
  • 文件处理 file-loader 与 url-loader
  • 多入口及自动清理

客位看官可直接 ctrl + f 搜索对应关键字

环境配置
  • window + r ,输入 cmd 打开命令行

  • 新建并进入 webpack-3.10.0 文件夹

    mkdir webpack-3.10.0 && cd webpack-3.10.0
    
  • 使用 sublime text3subl.exe 打开该文件夹

    subl.exe

  • webpack-3.10.0 目录下初始化操作,生成 package.json 文件

    npm init -y
    

也可以直接使用 npm init 来初始化 package.json 文件,但这样需要手动填写项目名之类的东西,加上 -y 表示使用默认配置

npm init -y

  • 新建 src 文件夹,今后将要打包的文件全部放入该文件夹下

    新建 src 文件夹

  • src 下新建 main.js 并随便敲一点代码

    main.js

  • 安装 webpack

    npm install webpack@3.10.0 --save-dev
    

这里是安装指定版本号的 webpack,不加版本号则是最新版

安装完成

安装完成后的 package.json

package.json

安装完成后的项目目录


新增了 node_modules 目录
  • 修改 package.json

    增加执行脚本语句

  • 打包

    #  命令语句        源文件        目标文件
    npm run start src/main.js dist/bundle.js
    

如果没有 dist 目录则自动新建

打包

  • 打包结果


    打包后
  • webpack-3.10.0 目录下创建 index.html 文件,引入之前打包好的 bundle.js 文件

<!DOCTYPE html>
<html>
<head>
    <title>webpack-3.10.0</title>
</head>
<body>
    <h1>Hello World!</h1>
    <script type="text/javascript" src="dist/bundle.js"></script>
</body>
</html>
打包并引入成功
  • 我们同样可以把打包的语句直接写在 package.json 中,免得每次输入很麻烦
    "start":"webpack src/main.js dist/bundle.js"
    

image.png

这样我们在命令行中直接调用 npm run start 也能实现打包的效果

  • 现在有个问题,当我们修改 main.js 文件的内容时,刷新页面并不会显示更新的改动,如果想让页面同步的话,我们还需再执行一次 npm run start 语句,每次这样未免太麻烦,可以通过以下几种方式改善:
    • 方法一:修改 package.json 中之前写好的 start 语句
    "start":"webpack src/main.js dist/bundle.js --watch",
    
    • 方法二:新定义一个 watch 命令,这种方式根据官方文档说明,由于调用的是之前自定义的 npm run start 命令,因此需要在 --watch 前额外添加 --
    # package.json
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "start":"webpack src/main.js dist/bundle.js",
      "watch":"npm run start -- --watch"
    },
    

package.json

以第二种方式为例:
监听成功

此时则监听成功,修改 main.js 保存则实时会在 bundle.js 中显示,页面中刷新即可展示;ctrl + c 终止监听。

实时监听

使用配置文件
  • 为了看出效果,我们先把之前生成的 bundle.js 文件删掉。
  • webpack-3.10.0 目录下创建 webpack.config.js ,并输入如下内容
#  webpack.config.js

var webpack = require("webpack");

module.exports = {
    entry:'./src/main.js', 
    output:{
        path:'./dist',        
        filename:'bundle.js'
    }
}

此时你的项目结构应该是这样的,dist 目录下 空空如也

dist 目录下为空

  • 跑一下试试

    报错

    原因是 output 中的路径需要是绝对路径 absolute path

  • 在配置文件中引入 path 模块解决绝对路径问题

    var webpack = require("webpack");
    var path = require("path");
    
    module.exports = {
        entry:'./src/main.js',
        output:{
            path:path.resolve(__dirname,'./dist'),
            filename:'bundle.js'
        }
    }
    
  • 由于添加了配置文件,因此需要修改一下 package.json 中的启动命令 npm run start 更改为如下(因为配置文件中已经设置了路径及文件名,因此不需要命令中再指定)

    "start":"webpack",
    
  • 跑一下


    跑跑

    同样是创建了 bundle.js 文件

    效果是一样的


CSS 处理
  • src 目录下创建 main.css
    # main.css
    body{
        background: orange;
    }
    
  • 修改 main.js
    # main.js
    require('./main.css')
    
  • 使用 npm run watch 命令会报错
    缺少 loader

    缺少 loader,这里引用官网说明:

loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。

  • 处理 css 需要安装一个 css-loader 的包:
    npm install css-loader --save-dev
    
安装成功
  • 安装完成后需要在配置文件中进行处理,注意 module 属性:
# webpack.config.js

var webpack = require("webpack");
var path = require("path");

module.exports = {
    entry:'./src/main.js',
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:'bundle.js'
    },
    module:{
        rules:[{
            test:/\.css$/,  //  正则匹配 .css 后缀
            use:'css-loader'
        }]
    }
}

再跑一下

修改配置文件之后

看一下是否被打包到 bundle.js
bundle.js

可以看到 main.css 的样式的确被打包到 bundle.js 中了,但为什么浏览器中没有效果?

  • 安装 style-loader
npm install style-loader --save-dev
  • 修改配置文件,注意:style-loader 需要写在前面
    修改配置文件
  • 再调用命令
    npm run watch 
    
样式已注入

将 ES6 代码编辑为所有浏览器通用的代码
  • main.js 内容改为一段 ES6 的代码
    # main.js
    let a = 11;
    const b = 22;
    
    class Foo{
    
    }
    
  • 直接调用 npm run watch 会发现 bundle.js 中的代码依旧为 ES6
    尚未安装 ES6
  • 这时需要 Babel 这个工具

Babel 的作用就是将下一代的 JavaScript 语法转换为现今浏览器兼容的语句

  • 首先安装 Babel
    npm install --save-dev babel-loader babel-core
    
  • webpack.config.js 中添加一条规则:
    { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
    
    其中,test 用于判断扩展名为 .js 的文件,exclude 表示不包括的文件。
    添加规则后,此时的 webpack.config.js 文件应该是这样的
    添加规则
  • 安装转换 ES2015 及更高版本 JavaScript 语法的 env preset
    npm install babel-preset-env --save-dev
    
  • 在根目录 webpack-3.10.0 下创建 .babelrc 文件,内容如下:
    {
      "presets": ["env"]
    }
    
创建 .babelrc
  • OK,现在执行命令 npm run watch,可以看到我们之前 main.js 中的语句在 bundle.js 中已经成功转换成通用语句了
    main.js

    bundle.js

    本节内容可直接参考 Babel 官网:https://babeljs.cn/

文件压缩
  • 文件压缩需要用 webpack 的插件来实现,比如 webpack 自带一个 BannerPlugin 插件,用于添加顶部注释,首先在 webpack.config.js 中添加如下代码:
    plugins:[
      new webpack.BannerPlugin('顶部注释插件')
    ]
    
  • 重新打包 npm run watch,成功后,bundle.js 中顶部出现注释
    添加成功
  • webpack 有个自带的插件 UglifyJsPlugin 用于压缩文件
plugins:[
  new webpack.BannerPlugin('顶部注释插件'),
  new webpack.optimize.UglifyJsPlugin()
]

重新打包后的 bundle.js

压缩后的 bundle.js

  • 然而我们在开发调试阶段是不需要压缩代码的,因此需要对开发环境和线上环境做个区分,开发环境不压缩代码,线上环境才压缩
    if(process.env.NODE_ENV === 'production'){
        module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
    }
    
    如果是线上环境,则将 UngifyJsPlugin 插件填入 webpackplugins
  • 回到命令行调用命令
    set NODE_ENV=production  // 设置为生产环境, windows 系统
    npm run watch
    
切换线上环境并打包
  • 我们可以直接在 package.json 中添加脚本命令(我尝试了几种写法,发现只有这样是有效的,不知道为什么。此外,有时这样也不好用,需要在命令行中手动制定一次 set NODE_ENV=production,之后调用 npm run production 就有效了)
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "start": "webpack",
      "watch": "npm run start -- --watch",
      "production":"set NODE_ENV=production && npm run watch",
      "development":"set NODE_ENV=development && webpack --watch"
    }
    

这样在命令行中通过 npm run development 即可切换为开发环境(代码不压缩),npm run production 就是生产环境(代码压缩)

开发生产环境切换

  • webpack.config.js 简单做一下整理
var webpack = require("webpack");
var path = require("path");
var isProduction = process.env.NODE_ENV === 'production'

module.exports = {
    entry:'./src/main.js',
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:'bundle.js'
    },
    module:{
        rules:[{
            test:/\.css$/,
            use:['style-loader','css-loader']
        },{ 
            test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
        }]
    },
    plugins:[
        new webpack.BannerPlugin('顶部注释插件'),
    ]
}

if(isProduction){
    module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
}

SASS 处理
  • 安装相关 loader
    npm install sass-loader node-sass webpack --save-dev
    
  • 这里我在安装 node-sass 时失败了,改为分别单独安装,node-sass 使用淘宝镜像 其他解决方案
    # 安装 sass-loader
    npm install sass-loader --save-dev
    # 安装 node-sass
    npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
    
  • 修改配置文件
    # webpack.config.js
    
      module:{
          rules:[{
              test: /\.scss$/,
              use: [
                  "style-loader", // creates style nodes from JS strings
                  "css-loader", // translates CSS into CommonJS
                  "sass-loader" // compiles Sass to CSS
              ]
          },{
              test:/\.css$/,
              use:['style-loader','css-loader']
          },{ 
              test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
          }]
      },
    
  • 修改 mian.js
    # main.js
    require('./main.scss')
    
  • 修改 main.cssmain.scss 并输入 scss 语句测试
    # main.scss
    $default:pink;
    body{
        background:$default
    }
    

重新打包,OK


sass 打包

CSS 与 JS 分离
  • 通常 webpack 建议所有文件都打包成一个单独的文件,这样可以减少网络请求。但如果有需要分类打包的话,需要使用 webpack 的一个外部插件 ExtractTextWebpackPlugin
  • 安装
    npm install --save-dev extract-text-webpack-plugin
    
  • 修改配置文件,注意注释部分
var webpack = require("webpack");
var ExtractTextPlugin = require("extract-text-webpack-plugin"); //  引入插件
var path = require("path");
var isProduction = process.env.NODE_ENV === 'production';


module.exports = {
    entry:'./src/main.js',
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:'[name].js'
    },
    module:{
        rules:[{
            test: /\.scss$/,
            use: ExtractTextPlugin.extract({        //  使用插件
                fallback: "style-loader",           //  用哪个 loader 加载
                use: [{
                    loader:"css-loader",
                    options:{
                        minimize:isProduction       //  是否压缩 css
                    }},
                    "sass-loader"]                  //  将资源转换为 css
            })
        },{ 
            test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
        }]
    },
    plugins:[
        new webpack.BannerPlugin('顶部注释插件'),
        new ExtractTextPlugin("[name].css"),        //  输出为 style.css 文件
    ]
}

if(isProduction){
    module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
}

文件处理 file-loader 与 url-loader
  • 首先在 src 目录下新建 images 目录并存入两个大小不一的图片

    新建目录并存入图片

  • index.htmlmain.scss 中引入两个图片

    index.html

    main.scss

  • 安装 file-loader

    npm install --save-dev file-loader
    
  • 修改配置文件

    module:{
        rules:[{
            test: /\.scss$/,
            use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: [{
                    loader:"css-loader",
                    options:{
                        minimize:isProduction
                    }},
                    "sass-loader"]
            })
        },{ 
            test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
        },{
            test:/\.png|jpe?g|gif$/,    // 匹配的图片格式
            use:['file-loader']         //  使用 file-loader
        }]
    }
    
  • 执行 npm run production,图片被打包并以 hash 方式重新命名

    图片打包

    打包后的 main.css

  • 也可以让图片以原有名字和后缀保存:

    {
          test:/\.png|jpe?g|gif$/,
          use:[{
              loader:'file-loader',
              options:{
                  name:'[name].[ext]'  // 以原有名字和后缀保存
              }
          }]
    }
    
原有名字和后缀
  • 也可以创建指定目录存放文件
    options:{
      name:'images/[name].[ext]'
    }  
    
    或,注意 outputPath/ 不能少
    options:{
      name:'[name].[ext]',
      outputPath:'images/'
    }
    

    效果就是这样


    我是效果
  • 至于 url-loader ,它可以限制图片的大小,小于一定值的图片将以 DataURL 直接嵌入在页面中,减少请求数
  • 安装
    npm install --save-dev url-loader
    
  • 修改配置文件
    use:[{
        loader:'url-loader',
        options:{
            limit:20480,    // 小于该值将嵌入页面
            name:'[name].[ext]',
            outputPath:'images/'
        }
    }]
    
  • 打包后可看到只有一个图片被打包,另一个图片直接嵌在了页面中:


    只有一张图片引入

    嵌入页面

多入口及自动清理
  • 尝试改一下入口属性
    entry:{app:'./src/main.js'},
    

这样生成的 jscss 文件将变成 app.jsapp.css

  • 先安装一个 jquery 包,注意名字小写
    npm install --save-dev jquery
    
  • 修改配置文件
    entry:{
        main:'./src/main.js',    // 将 main.js 打包成 main
        vendor:'jquery'          // 将 jquery 打包成 vendor
    }
    
多个入口
  • 自动清理需要 clean-webpack-plugin 插件
    npm install clean-webpack-plugin --save-dev
    
  • 如果我们在生成的文件中添加 hash 值会发现,每次打包由于 hash 导致名字的不同,进而会出现不同名的同文件,这显然不是我想要的。这个插件就可以用于每次打包前先清除指定目录或文件,避免重复。
  const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
+ const CleanWebpackPlugin = require('clean-webpack-plugin');

  module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
    plugins: [
+     new CleanWebpackPlugin(['dist']),
      new HtmlWebpackPlugin({
        title: 'Output Management'
      })
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容