Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I load node_modules in Cordova? (web browser modules, not node.js specific)

Tags:

npm

cordova

I have created a new Cordova app using

cordova create MyApp

I wanted to use a couple of web libraries (no dependency on node.js) and so I installed them with npm. E.g.

npm install onsenui vue-onsenui --save-dev

The directory structure looks like:

config.xml
hooks/
node_modules/
package.json
platforms/
plugins/
res/
www/

The index.html file in www has script tags to include the libraries

<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="onsenui.js"></script>
<script type="text/javascript" src="vue-onsenui.js"></script>

When running the cordova run browser command, the web server runs fine and displays the page as it should, including loading the cordova.js file, but it returns 404 for the other libraries.

Is there a way to use these node modules in Cordova without copying them into the www directory?

like image 702
Ben Avatar asked Sep 28 '17 10:09

Ben


2 Answers

Is there a way to use these node modules in Cordova without copying them into the www directory?

No, not easily: the contents of the www directory gets deployed to the native platform project by Cordova, unless explicitly copied by a hook script.

You could copy/symlink them into the www folder manually or use a hook script to automate this.

like image 189
DaveAlden Avatar answered Oct 15 '22 09:10

DaveAlden


TLDR and simple

Use the npm package: cordova-import-npm

Long question and DIY

You can use a hook before cordova prepare, that is, when the files are assembled for compiling.

  1. Edit your config.xml and add this line (not inside any platform but in the root, i.e. inside <widget):
<hook src="hooks/importNpmPackages.js" type="before_prepare"/>
  1. Create the file hooks/importNpmPackages.js with this content
const fse = require('fs-extra')
const path = require('path')
const twoSpaces = '  ' // for log indentation
var projectRoot

module.exports = function (context) {
  console.log(`${context.hook} : ${path.relative(context.opts.projectRoot, context.scriptLocation)}`)

  projectRoot = context.opts.projectRoot
  console.log(twoSpaces + 'Project root directory: ' + projectRoot)

  copyFile('jquery', path.join('dist', 'jquery.min.js'), path.join('js', 'res', 'jquery.min.js'))

  copyFile('bootstrap', path.join('dist', 'js', 'bootstrap.min.js'), path.join('js', 'res', 'bootstrap.min.js'))
  copyFile('bootstrap', path.join('dist', 'css', 'bootstrap.min.css'), path.join('css', 'res', 'bootstrap.min.css'))
}

function copyFile (npmPackage, // oficial name of the npm package from which the file is to be copied from
  fileRelativePath, // file path with respect to the main directory of the npm package (node_modules/<package>/)
  destFilePath) { // file's path to where it is copied, relative to the project www/ directory
  
  const packageDirFullpath = path.dirname(require.resolve(path.join(npmPackage, 'package.json')))
  const fileOriginFullPath = path.join(packageDirFullpath, fileRelativePath)
  const fileDestFullPath = path.join(projectRoot, 'www', destFilePath)

  fse.copySync(fileOriginFullPath, fileDestFullPath)

  const consoleMsg = npmPackage + ': ' +
    path.relative(projectRoot, fileOriginFullPath) + ' -> ' +
    path.relative(projectRoot, fileDestFullPath)
  console.log(twoSpaces + consoleMsg)
}

As you can see in this file I am copying jquery and bootsrap files using a function copyFile with this syntax:

copyFile(
  '<npmPackageName>',
  '<path/of/originFile/relative/to/packageDir>',
  '<path/to/destFile/relative/to/wwwDir>'
)

I use this in all my cordova projects and it works like a charm. That's how I see it

enter image description here

The hook is also triggered upon cordova build because cordova build equals to cordova prepare && cordova compile.

like image 34
João Pimentel Ferreira Avatar answered Oct 15 '22 08:10

João Pimentel Ferreira