Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webpack-从0开始写一个webapck v3 loader #9

Open
CodeLittlePrince opened this issue Jan 18, 2018 · 1 comment
Open

webpack-从0开始写一个webapck v3 loader #9

CodeLittlePrince opened this issue Jan 18, 2018 · 1 comment
Labels

Comments

@CodeLittlePrince
Copy link
Owner

CodeLittlePrince commented Jan 18, 2018

前言

有时候,市面上的webpack loader并不完全符合我们的需求,所以,我们不得不自己从0开始写一个,或者是在别人写的loader基础之上进行修改。
无论哪种,都需要我们对webpack加载loader的方式有所了解。

实现

出招吧~

在github上创建项目

创建本地项目

1、git clone项目到本地
2、初始化npm

npm init

填写完npm init的一路提示下来以后,我们看下文件结构:

.
├── README.md
└── package.json

3、安装webpack

npm i -D webpack

4、设置一下package.json里的scripts命令:

"scripts": {
  "dev": "webpack"
},

这样的话,基本的工具就准备完毕了。

编写webpack.config.js

1、创建webpack.config.js

.
├── README.md
├── node_modules
├── package-lock.json
├── package.json
└── webpack.config.js

2、编辑webpack.config.js

const path = require('path')

module.exports = {
  entry: {
    app: path.resolve('demo/index.js')
  },
  output: {
    path: path.resolve('dist'),
    filename: 'index.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: path.resolve('src/loader-test.js'),
        options: {
          speak: 'wang~',
        }
      }
    ]
  }
}

因为我们是从0开始编写的,所以不得不先从简单到复杂。
所以,如上,我们通过path引用的方式来使用loader。并且,我们配置了option,作为参数。
index则是需要处理的文件。

编写index.js

const cat = 'kitty'
console.log(cat)

编写loader-test.js

// loader-utils作为工具类引入(作为webpack依赖,所以在安装webpack时候就带上了)
const loaderUtils = require('loader-utils')

// loader调用的时候,会将源数据和sourcemap作为参数传入函数
module.exports = function(source, inputSourceMap) {
  const code = source
  const map = inputSourceMap
  // loaderUtils.getOptions 可以获取到设置loader时候设置的options
  // 当然loaderUtils还有很多其他有用的方法,详情可以看 https://github.com/webpack/loader-utils
  const loaderOptions = loaderUtils.getOptions(this) || {};
  console.log(source)
  console.log(loaderOptions)
  // loader需要将自己的值传给下一个loader,并且,loader不免会有异步操作
  // 因此需要回调来证明自己已经处理结束了
  this.callback(null, code, map)
}

先看下目录结构,为了不影响视觉,我忽略了node_module文件:

.
├── README.md
├── demo
│   └── index.js
├── package-lock.json
├── package.json
├── src
│   └── loader-test.js
└── webpack.config.js

好,让我们运行一下webpack,看一下效果:
npm run dev

...
const cat = 'kitty'
console.log(cat)
{ speak: 'wang~' }
...

正如我们写的loader,打印出了index.js的源码,以及,webpack.config.js配置loader时候的options。
是不是有点儿小兴奋?

写点有意义的功能

虽然说是教程,但是这样的小例子的确有点太过简单了,我们可以做点有意义点的功能。
比如,我们想把js中px全部替换成vw,比例就按照1vw = 10px吧。
(我相信很多朋友会觉得为啥替换js,而不是css或者scss。因为,会涉及更多的webapck配置,比较无聊和对本章内容没什么作用,所以,我觉得还是越简单越好,就拿js举例子吧)
好,计划有了,开始行动吧!

重新编辑index.js

const parentStyle = `
  background: #fdc;
  width: 1200px;
  height: 600px;
  box-sizing: border-box;
  padding: 150px 300px;
`
const childStyle = `
  background: #cdf;
  width: 600px;
  height: 300px;
`
const parent = document.getElementById('parent')
const child = document.getElementById('child')
parent.style.cssText = parentStyle
child.style.cssText = childStyle

为了更好展示,我们再写个html吧

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {padding: 0; margin: 0;}
  </style>
</head>
<body>
  <div id="parent">
    <div id="child"></div>
  </div>
</body>
</html>

让启动demo更顺畅

一不做二不休,为了更顺畅的看效果,我们加个webpack-dev-server自动启动吧。同时,顺带着,将html-webpack-plugin和clean-webpack-plugin也都加上。
关于写demo,我觉得,是写npm modules必须要有的东西,如果没有demo,没有顺畅的启动demo操作。别说别人懒得看,自己都懒得启动了。
好,我们再看下现在的webpack配置:

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

module.exports = {
  entry: {
    app: path.resolve('demo/index.js')
  },
  output: {
    path: path.resolve('dist'),
    filename: 'index.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: path.resolve('src/loader-test.js')
      }
    ]
  },
  plugins: [
    // 清理dist
    new CleanWebpackPlugin('dist'),
    // 将js打入html
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: path.resolve('demo/index.html'),
      chunks: ['app'] // 因为只有一个页面,这行不写也可以
    })
  ]
}

修改下package.json里的scripts命令:

"scripts": {
  "dev": "webpack-dev-server --open"
},

然后,启动实验一下,npm run dev
看下效果:

没问题,进入下一步~

正式修改loader

让我们重新编辑loader-test.js吧:

  ...
  // 替换px
  const regex = /(\d+?)px/g
  code = code.replace(regex, function(match, p1) {
    return p1/10 + 'vw'
  })
  ...
}

然后,再重新启动一下,我们会发现,px都被替换成了vw了,而且比例为1vw = 10px,成功!
当然,有同学肯定会想到,要是这个比例可以自己设置那就更好了。实现方式当然也很简单啊,还记得我们之前是怎么获取loader中options配置的speak吗?我相信同学完全可以独立完成了。

怎么把包做成npm module,然后发到npm 上,以后都能用呢?

这个的话,其实是我之前已经写过这样的文章了,同学们可以转到npm-从0开始写一个npm module

本文项目地址

没错~点我>>

最后,希望喜欢的同学能给star哦

说点题外话,不知道为什么webpack官网对loader的介绍那么简短,很难单单根据文档就写出loader来。所以还建议看些别人写的loader,如babel-loader等。

@CodeLittlePrince
Copy link
Owner Author

CodeLittlePrince commented Jan 10, 2020

回头看了下当年写的这文章,还是有很多问题的,官网其实有很完整的教程,建议直接参考官网:
writing-a-loader

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant