我爱编程

webpack从此不再是我们的痛点 — 核心基础

2018-04-16  本文已影响0人  ngaiwei

webpack一直是前端工程师的痛点,因为他的复杂、分散、loader、plugin这些第三方,让我们的学习成本陡然上升,使我们一直对他的配置模棱两可,今天带大家彻底明白他如何配置,摆脱困扰我们很久的痛点。本篇主要是webpack基础配置详解,关于webpack的模块chunk、编译阶段流程、输出阶段流程、loader的编写和手写plugin会在后续文章推出,为了避免错过可以关注我或者收藏我的个人博客www.ngaiwe.com

1.webpack是什么?

WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。并且跟具你的在项目中的各种需求,实现自动化处理,解放我们的生产力

2.项目初始化

mkdir webpack-start
cd webpack-start
npm init

3.webpack核心概念

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

1.Entry

context用来解决配置文件和入口文件不再同一层结构,列如我们配置文件在config,入口文件在根目录,则如下配置

module.exports = {
  context: path.join(__dirname, '..'), // 找到根目录
  entry: './main.js' //根目录下的入口文件
}

最简单的单页面(SPA)Entry入口,将main.js引入,并根据main.js中引用和依赖的模块开始解析

module.exports = {
  entry: './main.js'
}

多页面(MPA)Entry入口,将多个文件引入,当然一般是读取指定文件夹内的入口文件,然后引入

entry: {
  home: "./home.js",
  about: "./about.js",
  contact: "./contact.js"
}

如果是单页面(传入的是字符串或字符串数组),则chunk会被命名为main,如果是多页面(传入一个对象),则每个键(key)会是chunk的名称,描述了chunk的入口起点

2.Output

Object 指示webpack如何去输出,以及在哪里输出你的bundle、asset 和其他你所打包或使用 webpack 载入的任何内容

3.Module模块

处理项目中应用的不同模块,主要配置皆在Rules中,匹配到请求的规则数组,这些规则能够对模块应用loader,或者修改解析器parser

4.Resolve解析

主要用来模块如何被解析,给webpack提供默认值

5.Loader

通过使用不同的Loader,Webpack可以要把不同的文件都转成JS文件,比如CSS、ES6/7、JSX等,一般用于module的use中

module: {
  rules:[
      {
        test:/\.css$/,
        use:['style-loader','css-loader'],
        include:path.join(__dirname,'./src'),
        exclude:/node_modules/
      }
  ]      
}

具体相关loader需要查看你要引入的loader官方文档API,手写Loader会在下一篇文章具体介绍

6.Plugin插件

Array 扩展webpack,在webpack构建流程中的特定时机注入扩展逻辑来改变构建结果和想要做的事情,具体使用查看你引入的plugin官方文档,手写plugin会在后续文章中推出

7.webpack-dev-server

开发中的server,webpack-dev-server可以快速搭建起本地服务,具体使用查看 webpack-dev-server

8.Devtool

此选项控制是否生成,以及如何生成,官方推荐 SourceMapDevToolPluginsource-map-loader 建议看官方文档 Devtool 主要用来控制打包品质和在dev环境的调试便捷度和编译的快慢

9.Watch

webpack 可以监听文件变化,当它们修改后会重新编译和 HotModuleReplacementPlugin 有相似之处,监听文件变动热启动

4.配置webpack

webpack安装命令

npm install webpack webpack-cli -D

Webpack.config.js

具体用到的plugin插件

const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
// npm i extract-text-webpack-plugin@next // @next可以安装下一个非正式版本
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
let cssExtract = new ExtractTextWebpackPlugin({
    filename: 'css/css.css',
    allChunks: true
});
let lessExtract = new ExtractTextWebpackPlugin('css/less.css');
let sassExtract = new ExtractTextWebpackPlugin('css/sass.css');
/**
 * 有些时候我们希望把页面中的CSS文件单独拉出来保存加载
 * extract-text-webpack-plugin
 */
//let pages = ['index', 'base'];
// pages = pages.map(page => new HtmlWebpackPlugin({
//     template: './src/index.html',//指定产的HTML模板
//     filename: `${page}.html`,//产出的HTML文件名
//     title: `${page}`,
//     chunks: ['common', `${page}`],//在产出的HTML文件里引入哪些代码块
//     hash: true,// 会在引入的js里加入查询字符串避免缓存,
//     minify: {
//         removeAttributeQuotes: true
//     }
// }));
module.exports = {
    //先找到每个入口(Entry),然后从各个入口分别出发,找到依赖的模块(Module),
    //然后生成一个Chunk(代码块),最后会把Chunk写到文件系统中(Assets)   
    entry: './src/main.js',
    output: {
        path: path.join(__dirname, 'dist'),//输出的文件夹,只能是绝对路径 
        //name是entry名字main,hash根据打包后的文件内容计算出来的一个hash值
        filename: '[name].[hash].js' //打包后的文件名
    },
    resolve: {
        //引入模块的时候,可以不用扩展名 
        extensions: [".js", ".less", ".json"],
        alias: {//别名
            "bootstrap": "bootstrap/dist/css/bootstrap.css"
        }
    },
    //表示监控源文件的变化,当源文件发生改变后,则重新打包
    watch: false,
    watchOptions: {
        ignored: /node_modules/,
        poll: 1000,//每秒钟询问的次数
        aggregateTimeout: 500//
    },
    //devtool: 'source-map',//单独文件,可以定位到哪一列出错了
    // devtool: 'cheap-module-source-map',//单独文件,体积更小,但只能定位到哪一行出错
    // devtool: 'eval-source-map',//不会生成单独文件,
    // devtool: 'cheap-module-eval-source-map',//不会生成单独文件 只定位到行,体积更小
    /*
    loader有三种写法
    use
    loader
    use+loader
    * */
    module: {
        rules: [
            {
                test: require.resolve('jquery'),
                use: {
                    loader: 'expose-loader',
                    options: '$'
                }
            },
            {
                test: /\.js/,
                use: {
                    loader: 'babel-loader',
                    query: {
                        presets: ["env", "stage-0", "react"]
                    }
                }
            },
            {
                //file-loader是解析图片地址,把图片从源位置拷贝到目标位置并且修改原引用地址
                //可以处理任意的二进制,bootstrap 里字体
                //url-loader可以在文件比较小的时候,直接变成base64字符串内嵌到页面中
                test: /\.(png|jpg|gif|svg|bmp|eot|woff|woff2|ttf)/,
                loader: {
                    loader: 'url-loader',
                    options: {
                        limit: 5 * 1024,
                        //指定拷贝文件的输出目录 
                        outputPath: 'images/'
                    }
                }
            },
            {
                test: /\.css$/,//转换文件的匹配正则
                //css-loader用来解析处理CSS文件中的url路径,要把CSS文件变成一个模块
                //style-loader 可以把CSS文件变成style标签插入head中
                //多个loader是有顺序要求的,从右往左写,因为转换的时候是从右往左转换
                //此插件先用css-loader处理一下css文件
                //如果压缩
                loader: cssExtract.extract({
                    use: ["css-loader?minimize"]
                })
                //loader: ["style-loader", "css-loader", "postcss-loader"]
            },
            {
                test: /\.less$/,
                loader: lessExtract.extract({
                    use: ["css-loader?minimize", "less-loader"]
                })
                //use: ["style-loader", "css-loader", "less-loader"]
            },
            {
                test: /\.scss$/,
                loader: sassExtract.extract({
                    use: ["css-loader?minimize", "sass-loader"]
                })
                // use: ["style-loader", "css-loader", "sass-loader"]
            },
            {
                test: /\.(html|htm)/,
                loader: 'html-withimg-loader'
            }
        ]
    },
    plugins: [
        //用来自动向模块内部注入变量
        // new webpack.ProvidePlugin({
        //     $: 'jquery'
        // }),
        new UglifyjsWebpackPlugin(),
        new CleanWebpackPlugin([path.join(__dirname, 'dist')]),
        //此插件可以自动产出html文件
        new HtmlWebpackPlugin({
            template: './src/index.html',//指定产的HTML模板
            filename: `index.html`,//产出的HTML文件名
            title: 'index',
            hash: true,// 会在引入的js里加入查询字符串避免缓存,
            minify: {
                removeAttributeQuotes: true
            }
        }),
        new CopyWebpackPlugin([{
            from: path.join(__dirname, 'public'),
            to: path.join(__dirname, 'dist', 'public')
        }]),
        cssExtract,
        lessExtract,
        sassExtract
    ],
    //配置此静态文件服务器,可以用来预览打包后项目
    devServer: {
        contentBase: './dist',
        host: 'localhost',
        port: 8000,
        compress: true,//服务器返回给浏览器的时候是否启动gzip压缩
    }
}

5.总结

本篇偏向基础,能够搭建起简单的webpack配置,高级进阶会在后续文章推出,并且希望大家多去看官方API然后自我总结输出,只有将知识输出出来,才能更好的记忆和学习

6.博客

魏燃技术博客

有任何问题可留言或者发送本人邮箱ngaiwe@126.com

上一篇 下一篇

猜你喜欢

热点阅读