Webpack学习记录

// 一个常见的`webpack`配置文件
const 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-[hash].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: ExtractTextPlugin.extract({
                        fallback: "style-loader",
                        use: [{
                            loader: "css-loader",
                            options: {
                                modules: true,
                                localIdentName: '[name]__[local]--[hash:base64:5]'
                            }
                        }, {
                            loader: "postcss-loader"
                        }],
                    })
                }
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('123'),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new 一个这个插件的实例,并传入相关的参数
        }),
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin("style.css")
    ]
};

注:“_dirname”是node.js的一个全局变量,指向当前执行脚本所在的目录。

几个核心概念。

  • Entry: 入口,webpack执行构建的第一步将从Entry开始,可抽象成输入
  • Module: 模块,在Webpack里一切皆模块,一个模块对应一个文件。Webpack会从配置的Entry开始递归找出所有依赖的模块。
  • Chunk: 代码块,一个Chunk由多个模块组合而成,用于代码合并与分割。
  • Loader: 模块转换器,用于将模块的原内容按照需求转换成新内容。项目中需要的每个Loader都需要安装。
  • Plugin: 扩展插件,在Webpack构建流程中的特定时机注入扩展逻辑,来改变构建结果或做我们想要的事情。
  • Output: 输出结果,在Webpack经过一系列处理并得出最终想要的代码后输出结果。

Webpack在启动后会从Entry里面配置的Module开始,递归解析Entry依赖的所有Module。每找到一个Module,就会根据配置的Lodaer去找出对应的转换规则,对Module进行转换后,再解析出当前Module依赖的Module。这些模块会以Entry为单位进行分组,一个Entry及其所有依赖的Module被分到一个组也就是一个Chunk。最后,Webpack会将所有Chunk转换成文件输出。在整个流程中,Webpack会在恰当的时机执行Plugin里定义的逻辑。

DevServer

使用DevServer,DevServer会启动一个HTTP服务器用于服务网页请求,同时会帮助启动Webpack,并接收Webpack发出的文件变更信号,通过WebSocket协议自动刷新网页做到实时预览。

执行打包任务

可以在package.json里对scripts对象进行设置即可。

 {
  "scripts": {
    "start": "webpack-dev-server --open --hot --progress --colors --host localhost",
    "build": "rm -rf ./dist && webpack --progress --colors"
  },
 }

npm的start命令是一个特殊的脚本名称,其特殊性表现在,在命令行中使用npm start就可以执行其对于的命令,如果对应的此脚本名称不是start,想要在命令行中运行时,需要这样用npm run {script name}npm run build

--open --host localhost
//执行npm start后自动打开浏览器

resolve.alias && ProvidePlugin

有时候我们在项目中会需要频繁引入同一个路径的文件,如果需要引入的次数特别多,我们就得在每一次引入都要写一长串的地址,那么我们有没有什么方法可以偷点懒呢,我们可以通过调整webpack里的配置达到“偷一点小懒”的目的。

   resolve.alias这个配置项相当于为文件目录配置一个别名

使用resolve.alias配置的用法如下

module.exports = {
  entry: 
  {
    main:'./main.js',
  },
  output: {
    path:__dirname+'/dist',
    filename: '[name].js'
  },
  resolve:{
    //配置别名,在项目中可缩减引用路径
    alias: {
      vue$: 'vue/dist/vue.esm.js',
      '@': resolve('src'),
      '&': resolve('src/components'),
      'api': resolve('src/api'),
      'assets': resolve('src/assets')
    }
  },
  plugins: [
   
  ]
};

这样配置后在使用的时候就可以直接

import http from '@/utils/http'

代替

import http from 'src/utils/http'
reslove.alias可以让我们不用重复的去写一长串的路径,但是在使用的时候还是得引入,如果我们连引入都懒得引入呢?webpack为我们提供了ProvidePlugin这个帮我们解决问题的插件

那么ProvidePlugin要怎么使用呢?
webpack.config.js

const webpack = require('webpack')
module.exports = {
  entry: 
  {
    main:'./main.js',
  },
  output: {
    path:__dirname+'/dist',
    filename: '[name].js'
  },
  resolve:{
    //配置别名,在项目中可缩减引用路径
    alias: {
      
    }
  },
  plugins: [
    //提供全局的变量,在模块中使用无需用require引入
    new webpack.ProvidePlugin({
      $config: [resolve(`src/data/config/${process.env.CONFIG_ENV}.env.js`), 'default'],
    }),
  ]
};

使用的时候就可以寄直接将 $config作为一个全局变量来使用

编写一个plugin

plugin可以监听webpack处理过程中的关键事件,深度集成进webpack的编译器,可以说plugin的执行层面是整个构建过程。Plugin系统是构成webpack的主干,webpack自身也基于plugin系统搭建,webpack有丰富的内置插件和外部插件,并且允许用户自定义插件。

插件的组成部分

  • 一个javaScript命名函数,并暴露出去
  • 在插件函数的prototype上定义一个apply方法,注入complier对象
  • 指定一个绑定到webpack自身的事件钩子
  • 处理webpack内部实例的特定数据
  • 功能完成后调用webpack提供的回调
function MyPlugin(options) {}
// 2.函数原型上的 apply 方法会注入 compiler 对象
MyPlugin.prototype.apply = function(compiler) {
  // 3.compiler 对象上挂载了相应的 webpack 事件钩子 4.事件钩子的回调函数里能拿到编译后的 compilation 对象
  compiler.plugin('emit', (compilation, callback) => {
    ...
  })
}
// 1.独立的 JS 模块,暴露相应的函数
module.exports = MyPlugin

Compiler 和 Compilation

compiler对象和compilation对象是webpack插件开发中最重要的两个资源,那他们分别是什么呢?

  • compiler 对象代表了完整的 webpack 环境配置。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。

  • compilation 对象代表了一次资源版本构建。当运行 webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。一个 compilation 对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。

compiler 对象

compiler 即 webpack 的编辑器对象,在调用 webpack 时,会自动初始化 compiler 对象,源码如下:

// webpack/lib/webpack.js
const Compiler = require("./Compiler")

const webpack = (options, callback) => {
  ...
  options = new WebpackOptionsDefaulter().process(options) // 初始化 webpack 各配置参数
  let compiler = new Compiler(options.context)             // 初始化 compiler 对象,这里 options.context 为 process.cwd()
  compiler.options = options                               // 往 compiler 添加初始化参数
  new NodeEnvironmentPlugin().apply(compiler)              // 往 compiler 添加 Node 环境相关方法
  for (const plugin of options.plugins) {
    plugin.apply(compiler);
  }
  ...
}
compilation 对象

结合源码来理解下上面这段话,首先 webpack 在每次执行时会调用 compiler.run() (源码位置),接着追踪 onCompiled 函数传入的 compilation 参数,可以发现 compilation 来自构造函数 Compilation。

// webpack/lib/Compiler.js
const Compilation = require("./Compilation");

newCompilation(params) {
  const compilation = new Compilation(this);
  ...
  return compilation;
}

path.join()与path.resolve()的区别

path 是 node.js内置的package,用来处理路径

  • path.join([path1],[path2][,...])

    用于连接路径,对参数里的路径片段就行拼接

  • path.resolve([from...][,to])

    将to解析成绝对路径

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

推荐阅读更多精彩内容

  • webpack 核心 核心概述 entry 入口文件:js 代码文件,可执行的 node 模块或打包的入口文件。 ...
    coolheadedY阅读 3,462评论 1 6
  • webpack 构建 流程 webpack 整体是一个插件的架构,所有的功能都是插件的方式集成在构建流程中,通过发...
    Lyan_2ab3阅读 919评论 0 1
  • 基本打包原理 Webpack Loader Webpack Plugin HMR原理 Webpack的性能优化 构...
    大白兔奶糖味阅读 163评论 0 0
  • 工作原理概括 基本概念 Entry:入口,Webpack执行构建的第一步将从Entry开始,可抽象成输入。 Mod...
    Upcccz阅读 290评论 0 1
  • 写在前面:本文是webpack的一个学习笔记,涉及webpack打包流程、plugin、loader的编写、以及实...
    Bbang呀_阅读 405评论 0 2