纵横研究院前端基础技术专题社区

Webpack学习记录

2020-04-09  本文已影响0人  汉堡会有的
// 一个常见的`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的一个全局变量,指向当前执行脚本所在的目录。

几个核心概念。

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有丰富的内置插件和外部插件,并且允许用户自定义插件。

插件的组成部分

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 对象

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.resolve(_dirname, '/img')
    
console.log(_dirname) //当前文件所在文件夹的绝对路径
上一篇 下一篇

猜你喜欢

热点阅读