林秀栋的技术博客

webpack4.x 配置入门

安装

全局安装webpack

npm install -g webpack

当执行该操作后,便在C:\Users\你的用户名\AppData\Roaming\npm\node_modules创建了webpack文件夹,里面存储了刚刚全局安装的webpack模块。

我们在合适位置新建一个文件夹webpack-test,用于存放我们的项目。

命令行中定位到webpack-test文件夹下,输入以下命令进行项目的初始化:

npm init

这里,要求设置很多选项,可以按项目情况配置也可以不填直接回车。完成后,我们发现文件夹中增加了package.json文件,它用于保存关于项目的信息。

在根目录新建文件a.js,在命令行输入打包命令,将a.js打包成b.js

webpack a.js b.js

但会提示 p01

因为新版本中CLI(命令行工具)已转移到单独的包webpack-cli中,需额外安装

本地安装webpack-cli

npm install webpack-cli -D

打包依旧报错 p02

旧版本的webpack中,webpack指令要能在命令行中使用,需要全局安装webpack,而不是本地安装,因此这里的webpack-cli也应该是同理。

我们卸载本地安装的webpack-cli,全局安装webpack-cli:

npm uninstall webpack-cli

npm install -g webpack-cli

再次打包,依旧提示错误 p03

这里提示我们存在的第一个问题是没有配置webpack的mode选项,默认有production和development两种模式可以设置,因此我们尝试设为development模式,在命令行输入

webpack –mode development

我们看到进行了打包并显示了Hash、Version、Time、Build at信息,表明已经可以打包。不过,仍然有错误提示 p04 未找到入口模块

创建入口文件

webpack4.x以’./src/index.js’作为入口,我们需要在根目录创建src文件夹,将a.js移动到’./src’,并重命名为index.js。

现在如果我们再次执行

webpack index.js b.js

会提示can.t resolve相关的错误。

原因是,webpack4.x的打包已经不能用webpack 文件a 文件b的方式,而是直接运行webpack –mode development或者webpack –mode production,这样便会默认进行打包,入口文件是’./src/index.js’,输出路径是’./dist/main.js’,其中src目录即index.js文件需要手动创建,而dist目录及main.js会自动生成。

因此我们不再按webpack 文件a 文件b的方式运行webpack指令,而是直接运行

webpack –mode development

或者

webpack –mode production

这样便能够实现将’./src/index.js’打包成’./dist/main.js’。

不过每次都要输入这个命令,非常麻烦,我们在package.json中scripts中加入两个成员:

"dev":"webpack --mode development",
"build":"webpack --mode production"

以后我们只需要在命令行执行npm run dev便相当于执行webpack –mode development,执行npm run build便相当于执行webpack –mode production。

可以看到根目录下生成了dist目录,并且dist目录下生成了main.js文件,main.js文件已经打包了src目录下index.js文件的代码。

配置其他参数

我们如果需要配置webpack指令的其他参数,只需要在webpack –mode production/development后加上其他参数即可,如:

webpack –mode development –watch –progress –display-modules –colors –display-reasons

当然,这也可以写入package.json的scripts之中。

在根目录新建webpack.config.js

const config = {
    entry: {
        home: "./src/home.js",
        about: "./src/about.js",
        contact: "./src/contact.js"
    },
    output: {
        filename: '[name].js',
        path: __dirname + '/dist'
    }
};
module.exports = config;

上面是最简单的多页面输入输出配置

动态添加入口文件:

var glob = require('glob');

var webpackConfig = {
    entry:{}
};

// 获取指定路径下的入口文件
function getEntries(globPath) {
    var files = glob.sync(globPath),
        entries = {};

    files.forEach(function(filepath) {
        var split = filepath.split('/');
        var name = split[1].split('.')[0];
        //取src/a.js的a作为name
        entries[name] = './' + filepath;
    });
    return entries;
}

var entries = getEntries('src/*');

Object.keys(entries).forEach(function(name) {
    // 每个页面生成一个entry,如果需要HotUpdate,在这里修改entry
    webpackConfig.entry[name] = entries[name];
})
module.exports = webpackConfig;

上面webpackConfig中还有module、plugins等属性

比如

module: {
    rules: [
        { test: /\.css$/, use: ['style-loader', 'css-loader']  }
    ]
}

及style和css加载

还有

plugins:[]

然后可以在最外层引用插件var HtmlWebpackPlugin = require(‘html-webpack-plugin’);

使用

Object.keys(entries).forEach(function(name) {
    // 每个页面生成一个entry,如果需要HotUpdate,在这里修改entry
    webpackConfig.entry[name] = entries[name];

    // 每个页面生成一个html
    var plugin = new HtmlWebpackPlugin({
        // 生成出来的html文件名
        filename: name + '.[hash].html',//name + '.[hash].html',
        // 每个html的模版,这里多个页面使用同一个模版
        template: './src/a.html',
        // 自动将引用插入html
        inject: true,
		hash: true, //为静态资源生成hash值
        // 每个html引用的js模块,也可以在这里加上vendor等公用模块
        chunks: [name],
		minify: { //压缩HTML文件
			removeComments: true, //移除HTML中的注释
			collapseWhitespace: false //删除空白符与换行符
        }
    });
    webpackConfig.plugins.push(plugin);
})

如果入口文件引用了模块a和模块b,而模块b依赖模块a,直接按先后顺序加载模块a和b无效,需要在b中也引入模块a

如果入口文件和模块b都需要模块a,两个文件都引入了模块a,打包后模块a被打包进文件(比如k.js),根据测试,k.js中好像只会打包一次模块a

如果希望只在入口文件引入一次a.js,而b中不再引入也可以使用,可用expose-loader[推荐使用],把公共文件设置为全局,比如bootstrap只在jq为全局时可以使用,就可以用这个方法,使用方法

import $ from 'expose-loader?$!./jquery.min.js'
//格式 import 名字 from 'expose-loader? libraryName!./file.js'

或者在webpack.config.js的module.rules中加入

{
    test: require.resolve('./src/jquery.min.js'),
    use: [{
          loader: 'expose-loader',
          options: 'jQuery'
      },{
        loader: 'expose-loader',
        options: '$'
    }]
}

//然后入口文件中普通引入:
import $ from './jquery.min.js'
//如果是npm下载的jQ,上面不需要路径,直接写’ jquery’即可

其他方法:

1.在webpack中添加插件ProvidePlugin[不推荐使用,因为没把jq放在全局,一些插件还是无法使用]

plugins: [
    new webpack.ProvidePlugin({
        $: "jquery",
        jQuery: "jquery"
    }),
]
// $函数会自动添加到当前模块的上下文,无需显示声明

问题是依旧没有全局的$函数,所以导入插件依旧会失败,并且如果有eslint这样的preLoads,调用语句也难以通过语法校验(因为没有声明$就直接使用)

2.包装jquery[推荐使用]

//创建一个jq的包装文件jquery-vendor.js
//包装jq,把他放在全局
import $ from ./jquery.min.js';
window.$ = $;
window.jQuery = $;
export default $;
//然后在入口文件中,不引用jq而是引用包装文件
import $ from './jquery-vendor.js'