[Architect (Part 9)] How to make Node environment support ES Module

Get into the habit of writing together! This is the third day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .

Learn about modularity

Commonjs

  • Load the module:require
  • Export module:module.exports / exports.xxx

ES Module

  • Load the module:import
  • Export module:export default / export xxx

Pain point analysis

Use to Commonjsexport a moduleutils

// test-cli-0174\bin\utils.js
module.exports = function () {
  console.log('hello utils');
};
复制代码

Introduce modules in the main file by means ES Moduleof

// test-cli-0174\bin\index.js
#!/usr/bin/env node

import utils from './utils';

utils();
复制代码

Run the program and find that an error will be reported Cannot use import statement outside a module, which means that the importsyntax .

image.png

So how do we make the Nodeenvironment support ES Moduleit?

Use webpack

Install webpack

npm i -D webpack webpack-cli
复制代码

Modify the code

The main file uses requireto call webpackthe builtcore.js

// test-cli-0174\bin\index.js
#!/usr/bin/env node
require('./dist/core');
复制代码

core.jsuse es moduleimportutils.js

// test-cli-0174\bin\core.js
import utils from './utils';
utils();
复制代码

Configure webpack.config.js

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

module.exports = {
  entry: './bin/core.js',
  output: {
    path: path.join(__dirname, '/dist'),
    filename: 'core.js',
  },
  mode: 'development',
};
复制代码

Modify the scripts field of packag.json

  "scripts": {
    "build": "webpack",
    "dev": "webpack -w"
  },
复制代码

execute build

npm run build
复制代码

After the build is complete, the distdirectory and the builtcore.js

image.png

Run the program again and find that it can run normally.

image.png

You can start the listening state and automatically execute the build process when the file changes

npm run dev
复制代码

Support for Node built-in libraries via the webpack target attribute

When we call nodethe built-in library of , for example path、fs, the build will report an error, because the built-in library of the environment does not exist by defaultwebpack , so we need to modify the property to .webpackwebwebnodetargetnode

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

module.exports = {
  entry: './bin/core.js',
  output: {
    path: path.join(__dirname, '/dist'),
    filename: 'core.js',
  },
  target: 'node', // 默认是web
};
复制代码
// test-cli-0174\bin\utils.js
import { pathExistsSync } from 'path-exists';

export function exists(p) {
  return pathExistsSync(p);
}
复制代码
// test-cli-0174\bin\core.js
import path from 'path';
import { exists } from './utils';

console.log(path.resolve('.'));
console.log(exists(path.resolve('.')));
复制代码

Execute the program, there is no problem.

image.png

Use babel to be compatible with lower versions of node

Install dependencies

npm i -D 
babel-loader
@babel/core 
@babel/preset-env 
@babel/plugin-transform-runtime 
@babel/runtime-corejs3
复制代码

configurewebpack

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

module.exports = {
  entry: './bin/core.js',
  output: {
    path: path.join(__dirname, '/dist'),
    filename: 'core.js',
  },
  mode: 'development',
  target: 'node', // 默认是web
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|dist)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: [
              [
                '@babel/plugin-transform-runtime',
                {
                  corejs: 3,
                  regenerator: true,
                  useESModules: true,
                  helpers: true,
                },
              ],
            ],
          },
        },
      },
    ],
  },
};
复制代码

How node natively supports ES Module

The suffix of the file name needs to be modified .mjs, and once it is used mjs, all contents need to be used ES Moduleand cannot be mixed, otherwise an error will be reported.

// test-cli-0174\bin\index.mjs
#!/usr/bin/env node

import './core.mjs';
复制代码
// test-cli-0174\bin\core.mjs
import path from 'path';
import { exists } from './utils.mjs';

console.log(path.resolve('.'));
console.log(exists(path.resolve('.')));
复制代码
// test-cli-0174\bin\utils.js
import { pathExistsSync } from 'path-exists';

export function exists(p) {
  return pathExistsSync(p);
}
复制代码

Finally, execute the program with an instruction

node --experimental-modules bin/index.mjs
// node14版本之后 不需要加 --experimental-modules 指令也可以
node bin/index.mjs
复制代码

The same results can be obtained, no problem.

image.png

If you don't want to change the suffix name to , you can specify the field as .mjsin the project's package.jsonfile .typemodule

{
   "type": "module"
}
复制代码

Once set, the JSscripts are interpreted as ES6modules.

Guess you like

Origin juejin.im/post/7083291297343078413