Is there some way to trigger a webpack build without using the command line webpack build task in a node.js script? I know I can use the exec function to execute a command line task, but I'm looking for a way that doesn't involve the command line at all.
I'm looking for something that works like
import webpack from "webpack";
await webpack.build(...);
You can use the webpack Node API (https://webpack.js.org/api/node/).
Create a webpack instance, as specified in the docs, like so:
import webpack from 'webpack';
const compiler = webpack({}, (err, stats) => {
if (err || stats.hasErrors()) {
// ...
}
// Done processing
});
Then, use the run method on compiler to, as the docs say, "kickstart all compilation work".
compiler.run(() => console.log('Done'));
Related
(I have a Vue/Vite application but I think this question is generic to any setup.)
In my app, I have some code that I want to generalize into a separate npm library package so it can be used in multiple apps. This requires placing a file in the public folder of the app but I'm not sure what the best practice way of doing that is.
(This file is a service worker, but I think that is irrelevant to the question - this would be the same for any file that needs to have a public URL.)
I'd like the use of this library to be as clean as possible. That is, I'd like to not tell the client to "copy this file into your public folder".
I think that copy step needs to happen somewhere, though, unless there is a way to tell Vite to add a file to what it packages.
The copy step could be when running npm install, I guess. It would be nice if that could also add a line to .gitignore, too, if needed. I think this is complicated because the actual location is different whether the app is Vue, Nuxt, or some other framework.
I don't think the copy step could be when import mylib from "mylib" because that happens after the app is already packaged.
So, I think my two options are:
Tell Vite to put a particular file, unaltered, in the public folder.
Run a post install script when npm install runs. (That would have to work whether the user is on Windows, mac, or linux.)
Some other magic?
I don't know how to implement any of those, so a pointer to some documentation or a good term to search for would be appreciated, too.
Or is this just a fool's errand and I should tell the user to just copy the file to their public folder manually?
If you are using Vite, you can create an npm library with a Vite plugin in it. The documentation for Vite plugins is here, and the API that Vite's plugin API stems from is here. The code for a plugin to add to Vite's output and dev server would be
import { writeFile } from "fs";
import { resolve } from "path";
let url = "service-worker.js"
let fileContent = "file contents"
let outPath;
const myPlugin = () => ({
name: "add-service-worker",
configResolved(resolvedConfig) {
outPath = resolve(resolvedConfig.root, resolvedConfig.build.outDir, url);
},
configureServer(server) {
server.middlewares.use(`/${url}`, (req, res, next) => {
res.writeHead(200, { "Content-Type": "text/javascript" });
res.write(fileContent);
res.end();
});
},
closeBundle() {
writeFile(outPath, fileContent, { flag: "w" }, (error) => {
if (error) {
throw error;
}
console.log(`Generated file to ${outPath}`);
});
},
});
export default myPlugin;
The same could most likely be applied to a rollup or webpack plugin. However, the real easiest way would be to make this a library, and import it using
import service-worker from "service-worker"
I'm trying to code in Typescript an NPM package that should work as a CLI tool.
For simplicity, let's say that the package will take the default export from a config.js file written by the dev using the package and print it in the console.
So the dev will:
create a config.js file with export default 'hello world'
type npx someLibrary and see "hello world" in the terminal.
This use case is common in tools I've used like babel, jest, and webpack. Although I've already overcome some technical challenges around that, I am stuck in how to grab the future config.js file in Typescript.
The approach I'm trying to pursue is using dynamic imports. The compiler won't allow it, since the config file doesn't exist at coding time. The code is something like this:
main();
async function main(): Promise<void> {
const config = await import("./config.js");
console.log(config);
}
This causes the compiler error: Cannot find module './config.js' or its corresponding type declarations.ts(2307).
My question is: how can I tell typescript to import the config file that will be created in the future and be available only during runtime?
If that is impossible, how can I consume the content of that config file inside the Typescript program?
My question is: how can I tell typescript to import the config file that will be created in the future and be available only during runtime?
a. For a quick solution, you can simply put #ts-ignore on the line above your import. This should ignore the compilation error, and at runtime the file should be imported accordingly.
b. Alternatively you may also use require('./config.js') instead of using import. This should also get rid of the compilation error.
c. For a more proper solution, you can look into using a function to read the file at runtime. Two things you can consider using are fetch and fs
fetch
fetch('./config.js')
.then(response => response.text())
.then(text => console.log(text))
fs
import fs from 'fs'
const data = fs.readFileSync('./config.js', 'utf8')
console.log(data)
My current situation
Now I am using vue-cli#3.9.2. For some reason, I need to watch file change of my source code to run webpack's build, with vue-cli-service build --watch.
My current solution
Currently, I run another Node.js process to watch file change, of webpack's bundle. I really suffered from this terrible development experience.
Compare with vue-cli 2.x
When I used vue-cli 2.x, I actually run webpack(), one native API of webpack, in build/build.js, so I could use webpack().watch() instead to run build and pass my own script as callback function. However in vue-cli 3.x, there's no way and no need to approach the webpack's native API, within my knowledge.
Summary
I wish to run my own script after webpack's every auto build, though I could not find any guidance in vue-cli's official document.
From my understanding - you have a Webpack plugin use case. Just like for example webpack-build-notifier sends a notification after a rebuild.
I am not a Webpack plugin author, but this is already working for me:
// vue.config.js
const ArbitraryCodeAfterReload = function(cb) {
this.apply = function(compiler) {
if (compiler.hooks && compiler.hooks.done) {
compiler.hooks.done.tap('webpack-arbitrary-code', cb);
}
};
};
const myCallback = function() {
console.log('Implementing alien intelligence');
};
const plugins = [];
const isDev = process.env.NODE_ENV === 'development';
if (isDev) {
plugins.push(new ArbitraryCodeAfterReload(myCallback));
}
module.exports = {
configureWebpack: {
plugins
}
};
If this is not the right compilation step - the Webpack documentation should somewhere have the right hook for your use case.
Maybe there is already a plugin available which already does what you need...
Maybe this can help you. This is just an example. You only need to use &&
npm run start && npm run build
So after the npm run start script execute your npm run build script will run after the first one
Update you can use this package webpack-shell-plugin
const WebpackShellPlugin = require('webpack-shell-plugin');
new WebpackShellPlugin({
onBuildStart: [''],
onBuildEnd: ['']
})
I am using plugins in cypress and referred to https://docs.cypress.io/api/plugins/configuration-api.html#Usage. When we deploy them into jenkins, I am getting
`pluginsFile` is set to `/e2e/cypress/plugins/index.js`, but either the file is missing, it contains a syntax error, or threw an error when required. The `pluginsFile` must be a `.js` or `.coffee` file.
Please fix this, or set `pluginsFile` to `false` if a plugins file is not necessary for your project.[39m
Error: Cannot find module 'fs-extra'
I did go through a few threads which manually asks you to download the fs-extra in node_module. I did that and the dependency has been automatically added into the package.json file. However, the build fails. The code runs perfectly when you run locally and all the test passes. However, this fails when the deployed into jenkins.
// promisified fs module
const fs = require('fs-extra')
const path = require('path')
function getConfigurationByFile (file) {
const pathToConfigFile = path.resolve('cypress', 'config', `${file}.json`)
return fs.readJson(pathToConfigFile)
}
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
// accept a configFile value or use development by default
const file = config.env.configFile || 'environment-2'
return getConfigurationByFile(file)
}
The code should deploy successfully on Jenkins, however, evening installing it locally on node_module doesn't work. Can somebody help in figuring out what I am missing, please?
This issue has been resolved. Thanks to #Mr.J. This had nothing to do with fs-extra. The entry point in docker file was not correct and I had to modify that. After modifying that, it worked fine.
If at all you have this issue,
1. Try installing fs-extra inside node_module.
2. please check the path in the cypress config file.
3. Check the path in docker file.
I have a simple JS file that runs parcel bundler:
const Bundler = require('parcel-bundler');
(async () => {
const bundler = new Bundler('./src/index.html', {}); // options omitted for simplicity
await bundler.bundle();
})();
I run it from CLI with:
node ./build.js
While bundler works fine and creates bundled files in the dist folder, the process never exits, but rather remains in the async loop.
I tried adding then callback or using return but none of it helped.
Using process.exit() would of course stop the process but would also limit me from chaining this command in the CI, which is the whole purpose.
What am I doing wrong?
You need to set watch: false in your options to let Parcel know it should not watch but just build it once.
The default option is watch: true, so whenever you change something in your files, Parcel will recognize the change and rebuild your application.