Webpack 4 使用指南

11,559 阅读5分钟

最近想学一学Webpack,在网上看了很多相关文章,但是Webpack更新的太快了,很多文章都不适用weback新的版本,我从头开始研究了一番,在这里和大家分享交流一下,有错误的地方请指出.

简介

  • 从头开始搭建一个Webpack项目
  • 遇到的各种警告
  • 打包js文件
  • 处理css文件
  • 插件使用
  • 提取公共js库
  • webpack-dev-server 等...

一 . 搭建一个webpack项目

首先你需要一个node.js (我的版本 node v8.9.4, npm v5.6.0 )
创建一个文件夹 mkdir webpack-my 进入文件夹 cd webpack-my
创建项目 npm init 一路回车
安装webpack webpack-cli(想要执行webpack的命令必须有这个包)
--save-dev 是只添加依赖到开发环境
npm install --save-dev webpack webpack-cli
window下执行应该有几条警告 警告虽然没多大关系但我们还是来看一下
WARN nomnom@1.8.1: Package no longer supported... nomnom包过时了不用管它
WARN babel-preset-es2015@6.24.1 babel推荐让使用 babel-preset-env 我们下面再安装
WARN webpack-my@1.0.0 No repository field 没有仓库地址的警告可以在 npm init命令里设置或修改package.json:

"repository": {
    "type": "git",
    "url": "http://path.xxx"
}

或者设置 "private": true 设置为私有
webpack-my@1.0.0 No description 没写描述,基本同上...
两个 WARN SKIPPING OPTIONAL DEPENDENCY: fsevents@1.1.3 fsevent是mac osx系统的,警告忽略之... (微强迫症,警告不看全不舒服...)

二 . 处理js文件

1 . 安装babel

处理js文件我们需要用到bable,先安装一下
npm install --save-dev babel-loader babel-core

2 . 安装 babel-preset-env

它用来转义es6等 babel-preset-env介绍
npm install --save-dev babel-preset-env
在根目录下创建 .babelrc 文件, 加入以下代码

{
    "presets": ["env"]
}

3 . 解决浏览器兼容及性能问题

为防止浏览器不支持 Promise/Object.assign/Array.from等还有性能问题,我们引入两个包:

npm install --save-dev babel-polyfill babel-plugin-transform-runtime
引入生产版本依赖 npm install --save babel-runtime 通过 .babelrc 添加配置

{
    "presets": [
        "env"
    ],
    "plugins": [
       "transform-runtime"
    ]
}

babel-polyfill 需要在 webpack中配置下面会说到

4 . 让我们来配置一下webpack :

创建 src/bundle文件夹作为我们存放/生成代码的地方
创建 webpack.config.js 文件作为webpack的配置文件
path为node.js内置的,用来处理路径的, __dirname是node.js的全局属性,代表当前路径。
将 babel-polyfill 加到你的 entry 数组中使用
配置js文件要经过babel转义

const path = require('path');
module.exports = {
    //entry为入口,webpack从这里开始编译
    entry: [
        "babel-polyfill",
        path.join(__dirname, './src/index.js')
    ],
    //output为输出 path代表路径 filename代表文件名称
    output: {
        path: path.join(__dirname, './bundle'),
        filename: 'bundle.js'
    },
    //module是配置所有模块要经过什么处理
    //test:处理什么类型的文件,use:用什么,include:处理这里的,exclude:不处理这里的
    module: {
        rules: [
            {
                test: /\.js$/,
                use: ['babel-loader'],
                include: path.join(__dirname , 'src'),
                exclude: /node_modules/
            }
        ]
    },
};

好了让我们来试验一下,在src里创建 text-0.js text-1.js text-2.js index.js 内容分别为:

export const Text0 = "小明";
export const Text1 = "在公司";
export const Text2 = "写代码";
import {Text0} from './text-0.js';
import {Text1} from './text-1.js';
import {Text2} from './text-2.js';

const textFun = (...arg) => {
    let P = document.createElement("p");
    P.innerHTML = arg.join(" ");
    document.getElementById('root').appendChild(P);
}
textFun(Text0,Text1,Text2);

5 . 使用webpack

控制台输入 npx webpack --config webpack.config.js npx是什么
根据webpack.config.js打包文件
等等出现了什么 WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/ 原来是让我们设置开发或者生产模式
webpack.config.js 里设置

mode: 'development'

为了方便使用我们在 package.json 里加入webpack打包的命令方便我们使用修改 script

"scripts": {
    "build": "npx webpack --config webpack.config.js"
 },

这样再次运行我们直接输入 npm run build
js文件打包好了,让我们创建一个html页面看看效果吧,在bundle文件夹下创建 index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    </head>
    <body>
        <div id='root'></div>
        <script type="text/javascript" src="./bundle.js" charset="utf-8"></script>
    </body>
</html>

注意在这里写了一个script标签引入 bundle.js
打开html文件看看效果吧


如果你想看看打包出来的js文件,你可以在 webpack.config.js 里添加 devtool 属性 属性配置
图简单的话直接配置 devtool: '' 就可以了.

三 . 处理less文件

1 . 安装处理 css 相关 loader

npm install --save-dev css-loader style-loader
css-loader让你能import css  , style-loader能将css以style的形式插入

2 . 安装 less 相关

npm install --save-dev less less-loader

3 . 安装 postcsspostcss-cssnext 添加浏览器前缀

npm install --save-dev postcss-loader postcss-cssnext
创建 postcss.config.js 加入以下代码

module.exports = {
    plugins: {
        'postcss-cssnext': {}
    }
}

我在这里尝试 autoprefixer 插件但是好像不管用,可能还依赖别的包.

4 . 配置webpack

webpack.config.js -> module -> rules 里添加配置
处理顺序从右到左 less -> postcss -> css -> style

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

四 . 插件

1 . 生成HTML插件

安装插件
npm install --save-dev html-webpack-plugin 配置 webpack.config.js

const htmlWebpackPlugin = require('html-webpack-plugin');
...
plugins: [
    new htmlWebpackPlugin({
        filename: "index.html",  //打包后的文件名
        template: path.join(__dirname , "./src/index.html")  //要打包文件的路径
    })
],

src 文件夹里创建一个 index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    </head>
    <body>
        <div id='root'></div>
    </body>
</html>

html-webpack-plugin用法全解
删除 bundle 文件夹下所有文件
重新运行 npm run build 看看效果吧

2 . 生成CSS插件

安装插件(目前必须有@next)
npm install --save-dev extract-text-webpack-plugin@next
添加配置 webpack.config.js

const ExtractTextPlugin = require('extract-text-webpack-plugin');
...
module: {
    rules: [
        ...
        {
            test: /\.less$/,
            use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: ['css-loader', 'postcss-loader', 'less-loader']
            })
        }
    ]
},
plugins: [
    ...
    new ExtractTextPlugin({
        filename: 'index.css'
    }),
],

3 . 清理打包文件插件

上述代码所打出的包名称一直是一样的,很容易造成缓存问题
我们在 webpack.config.js 中做一下修改
outoup 下的 filename: 'bundle.js'filename: 'bundle.[hash:8].js'
plugins -> ExtractTextPlugin 下的 filename: 'index.css'filename: 'index.[hash:8].css'
缓存的问题解决了,但是我们每次生成的都是不同名字的文件 bundle 文件夹里的东西越来越多,我们需要一个插件来清理它.
安装插件 npm install --save-dev clean-webpack-plugin
修改 webpack.config.js

const CleanWebpackPlugin = require('clean-webpack-plugin');
...
plugins: [
    ...
    new CleanWebpackPlugin(['bundle'])
]
====== 2018.09.26 update ======

4 . 代码压缩件插件

npm install uglifyjs-webpack-plugin -D 安装代码压缩插件
修改 webpack.config.js

const uglify = require('uglifyjs-webpack-plugin');
...
plugins: [
    ...
    new uglify()
]

五 . 提取公共js

webpack.config.js 里添加

output: {
    ...
    chunkFilename: '[name].[chunkhash:8].js'
},
...
optimization: {
    splitChunks: {
        cacheGroups: {
            vendor: {
                test: /[\\/]node_modules[\\/]/,
                name: 'common',
                chunks: 'all'
            }
        }
    }
},

参考文章 webpack4 splitChunksPlugin && runtimeChunkPlugin 配置杂记

六 . webpack-dev-server配置

安装 webpack-dev-server
npm install --save-dev webpack-dev-server webpack.config.js 添加配置

...
devServer: {
    contentBase: path.join(__dirname, 'bundle'),  //启动路径
    host:'localhost',  //域名
    port: 8018,  //端口号
}

执行命令 npx webpack-dev-server --config webpack.config.js
为了方便使用添加 package.json 中,加入 --color(颜色) --progress(进度) --hot(热加载)

"scripts": {
    "build": "npx webpack --config webpack.config.js",
    "start": "npx webpack-dev-server --config webpack.config.js --color --progress --hot"
 },

七 . 编译图片

npm install --save-dev url-loader file-loader
webpack.config.js -> rules增加配置:

{
   test: /\.(png|jpg|gif)$/,
   use: [{
       loader: 'url-loader',
       options: {
           limit: 8192  //8k一下的转义为base64
       }
   }]
}

总结

到这里一个拥有基础功能的webpack包就建好了,后续有什么想到的东西我会继续更新...
以后可能会加上React , 项目的代码放在我的github
第一次写文章,有什么问题请告诉我~

====== 2018.5.13 update ======

笔者回来慢慢填坑了

八 . CSS Modules 使用

使用 CSS Modules 来模块化我们的CSS 修改我们的 webpack.config.js -> module -> rules

{
    test: /\.less$/,
    use: ExtractTextPlugin.extract({
        fallback: "style-loader",
-       use: ['css-loader', 'postcss-loader', 'less-loader'],
+       use: ['css-loader?modules&localIdentName=[local]-[hash:base64:5]', 'postcss-loader', 'less-loader']
    })
}

这样我们所有经过 rulesless 名字都被加了hash了
在我们的 index.less 中加入

.module-test{
    background-color: green;
    color: blue;
}

对应我们在 index.js 中加入

//替换之前的引入
import style from './index.less';

const textFun = (...arg) => {
    let P = document.createElement("p");
    P.innerHTML = arg.join(" ");
+   P.className = style["module-test"];
    document.getElementById('root').appendChild(P);
}

运行 npm run build
好了我们遇到一个问题,之前写的 #root 也被 CSS Modules 改变了 可是我们的 #root 是写在 index.html 里的
我们把 #root 改成这样 :global(#root) 这样就不会被改变了.

====== 2018.5.20 update ======

后续暂时没什么时间继续更新文章了(想开新坑...)。
我做了一些关于多页面打包、公共库提取、公共代码提取的配置
在我的 github
欢迎来访,同时求个star 求个Fork

====== 2018.07.15 update ======

热加载设置
webpack.config.js 中的 devServer 加入 hot: true
entry 入口添加 webpack/hot/only-dev-server 开启热加载
需要热加载的页面加入

if (module.hot) {
    module.hot.accept();
}

开启热加载

注意这种配置在多页面情况下只有首页可以热模块加载 其他的页面不行

====== 2018.07.16 update ======

加上 source-map 能看清楚错误在哪个文件
devtool: 'source-map'

参考文章

Webpack4 那点儿东西
从零搭建React全家桶框架教程
webpack中文网
babel中文网