《乘风破浪学webpack》

282 阅读3分钟

目标一:用webpack编译JS

首先下载webpack

然后由于是本地安装,所以需要指定在哪里去找webpack的执行程序

 ./node_modules/.bin/webpack --version

还有一种简易的方法,就是

npx webpack

npx 会自动帮我们找webpack在本地的哪个地方

当我们运行之后,

会发现多了一个dist文件,里面还有main.js 这就是转译index.js的结果

转译JS初体验

在index.js里写一些浏览器里不能直接用的ES6语法, 再用webpack转译,看能否使用

// index.js
import x from './x.js'
console.log(x)

// x.js
export  default 'xxxxx'

转译后的main.js:

也就是说webpack 敏锐地发现了其实我们的目标就是要打印'xxxxx'这个字符串

加上webpack的配置文件

webpack.config.js

const path = require('path');
module.exports = {
    mode: "development",
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[contenthash].js'
    }
}

目标二:理解文件名中hash的用途

小知识点:HTTP响应头里的Cache-Control

HTTP缓存的作用

内容哈希就是每次修改之后,会生成一次新的哈希值,所以文件名会变化

所以: 如果内容不更新,就一直缓存,如果更新,就用新的文件名重新发送请求

加一个哈希值就相当于给文件加了一个版本号

所以文件名中hash的用途就是便于增加缓存

同时,由于每次重新执行webpack, 都会生成一个js文件,所以为了不占用过多内存,我们每次执行时,应该先删除现有的dist文件夹,再执行

于是要配置一下package.json

"scripts": {
    "build": "rm -rf dist && webpack",  // 就是这一句
    "test": "echo "Error: no test specified" && exit 1"
  },

以后每次 yarn build , 就会执行"rm -rf dist && webpack", 即先删除,再重新编译

目标三 用webpack生成html

安装

yarn add --dev html-webpack-plugin

再yarn build 就会自动生成一个index.html

此时的webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    mode: "development",
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[contenthash].js'
    },
    plugins: [new HtmlWebpackPlugin({
        title: 'My App',
        template: "src/assets/index.html"
    })]
}

以上代码是说按照 "src/assets/index.html" 为模板,title为MY APP生成一个网页

src/assets/index.html:

<!doctype html>
<html lang="ch-ZN">
<head>
	<meta charset="UTF-8">
	<meta name="viewport"
				content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
  // 根据配置里的title生成 title
	<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
</body>
</html>

目标四 用webpack 引入CSS

直接引入CSS报错:

说需要一个css loader

下载即可

yarn build --dev css-loader

yarn build --dev style-loader

再修改配置文件

webpack.config.js

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

然后再yarn build

然后如果引入css, webpack 就会把css标签读出来放到style标签里

红色圈中的就是加载的css

现在我们把css放进了style标签

但如果我们希望单独抽成css文件呢?

下载插件:

yarn add --dev mini-css-extract-plugin

添加配置:

webpack.js.org/plugins/min…

目标五:简化编译

每次修改css, 首先是在dist文件夹里 http-server -c-1 开启服务器,如果要修改,就要断掉服务器,然后再改css, 再重新yarn build, 太麻烦了。

所以我们想要简化这一过程,需要用到webpack-dev-server

首先安装

yarn add --dev webpack-dev-server

配置方法:

webpack.js.org/guides/deve…

然后每次启动从yarn build, 改成 yarn start

这样每次运行后,就会自动打开浏览器

目标六:根据模式选择不同的编译

目标:开发模式下,把css生成为style标签

在生产production模式下,把css单独抽成文件

在开发时,我们用yarn start,

在生产时,我们用yarn build,css生成style标签

我们能不能配两个config文件,实现这种需求

package.json

"scripts": {
    // 这里指定webpack.config.prod.js的路径,参数是--config
    "build": "rm -rf dist && webpack --config webpack.config.prod.js",  
    "start": "webpack-dev-server --open",
    "test": "echo "Error: no test specified" && exit 1"
  },
webpack.config.js
 module: {
        rules: [
            {
                test: /.css$/i,
                // 下面这行表示生成style标签
                use: ['style-loader', 'css-loader']
            },
          }
         
webpack.config.prod.js

module: {
        rules: [
            {
                test: /.css$/i, 
                 // 下面这行表示生成css文件
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            },

但是问题是,这两个文件只有少数几行不一样,其他都完全一样,有没有更好的办法?

有!使用JS的继承思想

首先我们准备一个webpack.config.base.js 把所有的公共属性都放进去

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './src/index.js',
    devtool: 'inline-source-map',
    devServer: {
        contentBase: './dist',
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[contenthash].js'
    },
    plugins: [new HtmlWebpackPlugin({
        title: 'My App',
        template: "src/assets/index.html"
    })
    ],
    module: {
        rules: [
            {
                test: /.js$/i,
                enforce: 'pre',
                use: ['source-map-loader'],
            },
        ]
    }
}

然后webpack.config.js 和 webpack.config.prod.js分别继承这个base.js

首先引入,然后用...base即可引入Base的所有属性

有一个点需要注意:

如果是不希望全部覆盖掉base里的东西,而是希望继承一部分,修改一部分,可以在属性内部...base.module.rules

module: {
        rules: [
           // 先继承需要的
           ...base.module.rules,
          // 再叠加我自己的, 这样就不会用我自己的这个配置覆盖掉之前的所有配置
            {
                test: /.js$/i,
                enforce: 'pre',
                use: ['source-map-loader'],
            },
        ]
    }

最终修改好的配置文件分别是:

webpack.config.js


// 引入Base
const base = require('./webpack.config.base')

module.exports = {
    ...base, // 把所有的base里的配置都加载进来
    mode: "development",
    module: {
        rules: [
            {
                test: /.css$/i,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
}
webpack.config.prod.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 引入Base
const base = require('./webpack.config.base')

module.exports = {
    ...base,
    mode: "production",
    plugins: [
       // 先继承需要的
        ...base.plugins,
       // 再叠加我自己的, 这样就不会用我自己的这个配置覆盖掉之前的所有配置
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css',
            chunkFilename: '[id].[contenthash].css',
        })
    ],

    module: {
        rules: [
           // 先继承需要的
           ...base.module.rules,
          // 再叠加我自己的, 这样就不会用我自己的这个配置覆盖掉之前的所有配置
            {
                test: /.css$/i,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            }
        ]
    }
}

本文为fjl的原创文章,著作权归本人和饥人谷所有,转载务必注明来源