VUE

从零搭建基于Webpack4的开发环境

2020-02-08  本文已影响0人  MrRuo

webpack是当前最流行的模块化,为了更好地理解和学习webpack,本文从零搭建基于webpack开发环境。

代码地址

项目初始化

进入项目目录,生成package.json文件。因为我们并不是要做一个工具库,所以可以将main字段删除。main字段的主要作用是,通过import引入我们的程序,默认引入的具体文件。

npm init -y
// package.json
{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

配置package.json执行文件

运行npm run start之后,启动开发服务器,文件数据放在内存中,不会生成打包之后的dist文件。

运行npm run build之后,执行打包命令,生成打包后的dist文件。

// package.json
{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

运行命令之前,需要先配置webpack。

安装webpack的依赖

npm i webpack webpack-cli webpack-dev-server -D
目录结构

配置入口(entry)

因为我们构建的是单页面应用,所以entry的值可以是字符串,直接写入入口文件的相对路径。

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

新建入口文件 /src/main.js

目录结构

entry的值也可以是对象,用来支持多页面应用的打包。我们在这里打包的是单页面应用,使用字符串的形式就足够了。

// webpack.config.js
module.exports = {
  entry: {
    home: "./home.js",
    about: "./about.js",
    contact: "./contact.js"
  }
}

配置出口(output)

出口(ouput)决定了在什么位置输出、如何输出以及如何命名打包后的文件。

filename中的[name]是入口文件名称的占位符,是entry是对象情况下的key,在entry是字符串的时候,[name]的值为main

类似的展位符还有[id]内部chunk的id,[hash]唯一hash值以及[chunkhash]每个chunk内容生成的hash。

output的参数还有很多,对于打包库文件比较有用的librarylibraryTarget,具体使用可以查阅文档

// webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
      filename: '[name].bundle.js',
      path: path.resolve('dist')
  }
}

配置mode

mode告知webpack的打包环境是开发环境(development)还是生产环境(production)。可以根据不同的mode,运行不同的webpack配置。

在这里我们用npm运行脚本的时候,通过NODE_ENV可以来设置环境变量。在webpack.config.js获取之后,进行设置。

可以通过下面的形式对NODE_ENV进行设置。

// mac & linux
export NODE_ENV=production

// window
set NODE_ENV=production

为了解决平台兼容性的问题,可以使用cross-env

cnpm i cross-env -D

并更改package.json

// package.json
{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "start": "cross-env NODE_ENV=development && webpack-dev-server",
    "build": "cross-env NODE_ENV=production && webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {...}
}

并在webpack.config.js中获取,并设置。

// webpack.config.js

...

const mode = process.env.NODE_ENV;

module.exports = {
  entry: './src/main.js',

  ...

  mode
}

配置sourceMap

sourceMap是一个源文件和打包之后文件的对应关系表。配置之前,所有的log信息的位置、行号都是对应打包之后的文件。只有配置之后,才能让log的信息显示正确的位置(源文件位置)。

sourceMap有很多种类型,为了构建效率,开发环境下推荐使用cheap-module-eval-source-map,生产环境下可关闭。

// webpack.config.js

...

module.exports = {
  entry: './src/main.js',
  
  ...

  devtool: mode === 'development'
    ? 'cheap-module-eval-source-map'
    : 'none'
}

下面是从webpack官网截取的不同种类source map的分类图。

source map

配置loader

开发过程中,需要使用ES6的新特性提高开发效率。为了兼容低版本浏览器,需要引入babel将将ES6代码转换为低版本浏览器也能够识别的ES5代码。

npm i babel-loader @babel/core core-js@3 regenerator-runtime  @babel/preset-env -D
// webpack.config.js

...

module.exports = {
  entry: './src/main.js',
  
  ...

  module: {
    rules: [
      { 
        test: /\.js$/, 
        exclude: /node_modules/, 
        loader: 'babel-loader',
      }
    ]
  }
}

根目录下新建.babelrc文件,并添加babel相关配置。

目录结构
// .babelrc
{
  "presets": [
    [
      "@babel/preset-env", {
        "corejs": 3,
        "useBuiltIns": "usage"
      }
    ]
  ]
}

babel的编译功能是依赖于babel中的pluginpresetplugin的集合。

我们在这里配置了presetbabel-preset-env用于ES6转ES5, preset的运行顺序是从下至上。如果我们要配置其他的preset一定要注意配置顺序。

babel-preset-env中,useBuiltIns参数决定了babel如何处理pollyfill。值可以是usageentryfalse,默认是false。当设置useBuiltIns参数时(不为false),我们还需要引入core-js

当使用useBuiltIns: "entry"时,在入口文件中一次性手动引入时,不推荐使用。

当使用useBuiltIns:“usage”提取文件中所需的polyfill在每个文件引入,每种polyfill只会引入一次。

package.json中配置browserslist,让babel编译成响应的版本。该配置对后面的postcss同样有效。

// package.json
{
  "name": "webpack-demo",
  
  ...

  "browserslist": [
    "iOS >= 7",
    "Android > 4.1"
  ]
}

后续的loader同样配置在module.rules中,和babel-loader同级。

eslint一个用来识别 ECMAScript 并且按照规则给出报告的代码检测工具。

命令行输入npx eslint --init,按照提示进行安装。

这样我们的eslint就安装好了,添加package.json的eslint代码检查命令。

// package.json

{
  "name": "webpack-demo",
  ...
  "scripts": {
    "start": "cross-env NODE_ENV=development webpack-dev-server",
    "build": "cross-env NODE_ENV=production webpack",
    "lint": "eslint src"
  },
  ...
}

在命令行中输入 npm run lint,就可以运行eslint检查代码了。为了更多的在webpack中使用eslint,需要安装eslint-loader

npm i eslint-loader -D

同时还要更改webpack.config.js

// webpack.config.js

...

module.exports = {
  entry: './src/main.js',
  
  ...

  module: {
    rules: [
      { 
        test: /\.js$/, 
        exclude: /node_modules/, 
        use: [ 'babel-loader', 'eslint-loader' ]
      }
    ]
  }
}

webpack如果要引入非js文件,需要引入相应的loader才能识别。

除了必须的style-loadercss-loader之外,还引入了scss-loader来解析scss文件,以及postcss-loader帮助我们更好的管理css。

npm i style-loader css-loader sass-loader node-sass postcss-loader autoprefixer -D

根目录下新建postcss.config.js配置postcss,自动添加浏览器前缀,解决低版本浏览器的css兼容性问题。

目录结构
// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer')
  ]
}
// webpack.config.js

...

{
  test: /\.scss$/,
  use: [
    'style-loader', 
    {
      loader: 'css-loader',
      options: {
        importLoaders: 2
      }
    },
    'sass-loader',
    'postcss-loader'
   ]
},
{
  test: /\.css$/,
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        importLoaders: 1,
      }
    },
   'postcss-loader'
  ]
}

...

url-loader可以让小于指定大小的图片转换为Base64直接在页面中引入,大于指定大小的图片拷贝到目标文件夹。

npm i url-loader -D
// webpack.config.js

...

{
  test: /\.(jpg|png|gif)$/,
  use: {
    loader: 'url-loader',
    options: {
      name: '[name]_[hash].[ext]',
      outputPath: 'images/',
      limit: 10240
    }
  } 
}

...

配置Plugin

每次打包之前,清楚原先的打包后的文件。

cnpm i clean-webpack-plugin -D
// webpack.config.js

...

const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: './src/main.js',
 
  ...


  plugins: [
    new CleanWebpackPlugin()
  ]
}

文件打包好之后,需要通过html引入,才能够在浏览器中渲染。

html-webpack-plugintemplate参数指定了html模版位置。

cnpm i html-webpack-plugin -D
// webpack.config.js

...

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

module.exports = {
  entry: './src/main.js',
  
  ...

  plugins: [
    ...
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
}

启用 HMR之后,我们在更改代码时,只更改需要更改的组件,不会刷新页面,保留页面状态。

webpack内置HMR相关插件,所以我们要引入webpack,并将HotModuleReplacementPlugin插件加入配置,完成对js的 HMR配置。

不需要担心css文件,因为style-loader已经自动完成了。

// webpack.config.js

...

const webpack = require('webpack');

module.exports = {
  entry: './src/main.js',
  ...
  plugins: [
    ...
    new webpack.HotModuleReplacementPlugin()
  ]
}

配置开发服务器

// webpack.config.js

...

module.exports = {
  entry: './src/main.js',
  ...
  devServer: {
    hot: true,   // 热更新
    open: true,  // 自动开启浏览器打开页面
    port: 8080   // 端口号
  }
}

配置解析(resolve)

配置默认拓展名 resolve.extensions,不加后缀也可以通过impot引入到相应文件。
配置目录别名resolve.alias,方便找到常用目录。

// webpack.confgi.js

...

module.exports = {
  entry: './src/main.js',
  ...
  resolve: {
    extensions: [ '.js', '.json' ],
    alias: {
      src: path.resolve(__dirname, 'src/')
    }
  }
}

配置优化(optimization)

代码分割

// webpack.config.js

...

module.exports = {
  entry: './src/main.js',
  ...
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  }
}
上一篇下一篇

猜你喜欢

热点阅读